From 8342abaeec92e32740c799feeb6a97bd7343b3cb Mon Sep 17 00:00:00 2001 From: Anonymous Date: Tue, 14 Jan 2014 09:33:54 -0700 Subject: [PATCH] Added sharedTerrain library --- engine/shared/library/CMakeLists.txt | 1 + .../library/sharedTerrain/CMakeLists.txt | 11 + .../include/public/sharedTerrain/Affector.h | 1 + .../public/sharedTerrain/AffectorColor.h | 1 + .../sharedTerrain/AffectorEnvironment.h | 1 + .../public/sharedTerrain/AffectorExclude.h | 1 + .../sharedTerrain/AffectorFloraDynamic.h | 1 + .../sharedTerrain/AffectorFloraStatic.h | 1 + .../public/sharedTerrain/AffectorHeight.h | 1 + .../public/sharedTerrain/AffectorPassable.h | 1 + .../public/sharedTerrain/AffectorRibbon.h | 1 + .../public/sharedTerrain/AffectorRiver.h | 1 + .../public/sharedTerrain/AffectorRoad.h | 1 + .../public/sharedTerrain/AffectorShader.h | 1 + .../include/public/sharedTerrain/Array2d.h | 1 + .../public/sharedTerrain/BitmapGroup.h | 1 + .../include/public/sharedTerrain/Boundary.h | 1 + .../public/sharedTerrain/ColorRamp256.h | 1 + .../sharedTerrain/ConfigSharedTerrain.h | 1 + .../public/sharedTerrain/CoordinateHash.h | 1 + .../public/sharedTerrain/EnvironmentGroup.h | 1 + .../public/sharedTerrain/FastKeyList.h | 1 + .../include/public/sharedTerrain/FastList.h | 1 + .../include/public/sharedTerrain/Feather.h | 1 + .../include/public/sharedTerrain/Filter.h | 1 + .../public/sharedTerrain/FirstSharedTerrain.h | 1 + .../include/public/sharedTerrain/FloraGroup.h | 1 + .../public/sharedTerrain/FloraManager.h | 1 + .../public/sharedTerrain/FractalGroup.h | 1 + .../include/public/sharedTerrain/HeightData.h | 1 + .../ProceduralTerrainAppearance.h | 1 + .../ProceduralTerrainAppearanceTemplate.h | 1 + .../public/sharedTerrain/RadialGroup.h | 1 + .../SamplerProceduralTerrainAppearance.h | 1 + ...mplerProceduralTerrainAppearanceTemplate.h | 1 + ...SamplerProceduralTerrainAppearance_Cache.h | 1 + .../public/sharedTerrain/ServerFloraManager.h | 1 + .../ServerProceduralTerrainAppearance.h | 1 + ...erverProceduralTerrainAppearanceTemplate.h | 1 + .../ServerProceduralTerrainAppearance_Cache.h | 1 + .../ServerSpaceTerrainAppearance.h | 1 + .../ServerSpaceTerrainAppearanceTemplate.h | 1 + .../public/sharedTerrain/SetupSharedTerrain.h | 1 + .../public/sharedTerrain/ShaderGroup.h | 1 + .../sharedTerrain/SpaceTerrainAppearance.h | 1 + .../SpaceTerrainAppearanceTemplate.h | 1 + .../public/sharedTerrain/TerrainAppearance.h | 1 + .../public/sharedTerrain/TerrainGenerator.h | 1 + .../sharedTerrain/TerrainGeneratorLoader.h | 1 + .../sharedTerrain/TerrainGeneratorType.def | 1 + .../sharedTerrain/TerrainGeneratorType.h | 1 + .../sharedTerrain/TerrainModificationHelper.h | 1 + .../public/sharedTerrain/TerrainObject.h | 1 + .../public/sharedTerrain/TerrainQuadTree.h | 1 + .../TerrainReferenceObjectNotification.h | 1 + .../public/sharedTerrain/WaterTypeManager.h | 1 + .../library/sharedTerrain/src/CMakeLists.txt | 140 + .../ProceduralTerrainAppearance.cpp | 1547 +++++++++++ .../appearance/ProceduralTerrainAppearance.h | 456 ++++ .../ProceduralTerrainAppearanceTemplate.cpp | 1115 ++++++++ .../ProceduralTerrainAppearanceTemplate.h | 249 ++ .../SamplerProceduralTerrainAppearance.cpp | 1498 +++++++++++ .../SamplerProceduralTerrainAppearance.h | 158 ++ ...lerProceduralTerrainAppearanceTemplate.cpp | 501 ++++ ...mplerProceduralTerrainAppearanceTemplate.h | 70 + ...mplerProceduralTerrainAppearance_Cache.cpp | 392 +++ ...SamplerProceduralTerrainAppearance_Cache.h | 53 + .../ServerProceduralTerrainAppearance.cpp | 1257 +++++++++ .../ServerProceduralTerrainAppearance.h | 161 ++ ...verProceduralTerrainAppearanceTemplate.cpp | 78 + ...erverProceduralTerrainAppearanceTemplate.h | 50 + ...erverProceduralTerrainAppearance_Cache.cpp | 334 +++ .../ServerProceduralTerrainAppearance_Cache.h | 50 + .../ServerSpaceTerrainAppearance.cpp | 30 + .../appearance/ServerSpaceTerrainAppearance.h | 37 + .../ServerSpaceTerrainAppearanceTemplate.cpp | 67 + .../ServerSpaceTerrainAppearanceTemplate.h | 50 + .../appearance/SpaceTerrainAppearance.cpp | 38 + .../appearance/SpaceTerrainAppearance.h | 39 + .../SpaceTerrainAppearanceTemplate.cpp | 565 ++++ .../SpaceTerrainAppearanceTemplate.h | 160 ++ .../shared/appearance/TerrainAppearance.cpp | 457 ++++ .../src/shared/appearance/TerrainAppearance.h | 126 + .../src/shared/appearance/TerrainQuadTree.cpp | 1017 +++++++ .../src/shared/appearance/TerrainQuadTree.h | 741 +++++ .../src/shared/core/ConfigSharedTerrain.cpp | 88 + .../src/shared/core/ConfigSharedTerrain.h | 36 + .../src/shared/core/FirstSharedTerrain.h | 18 + .../src/shared/core/SetupSharedTerrain.cpp | 93 + .../src/shared/core/SetupSharedTerrain.h | 53 + .../src/shared/core/WaterTypeManager.cpp | 248 ++ .../src/shared/core/WaterTypeManager.h | 71 + .../src/shared/flora/FloraManager.cpp | 48 + .../src/shared/flora/FloraManager.h | 34 + .../src/shared/flora/ServerFloraManager.cpp | 25 + .../src/shared/flora/ServerFloraManager.h | 26 + .../src/shared/generator/Affector.cpp | 454 ++++ .../src/shared/generator/Affector.h | 200 ++ .../src/shared/generator/AffectorColor.cpp | 616 +++++ .../src/shared/generator/AffectorColor.h | 213 ++ .../shared/generator/AffectorEnvironment.cpp | 161 ++ .../shared/generator/AffectorEnvironment.h | 86 + .../src/shared/generator/AffectorExclude.cpp | 101 + .../src/shared/generator/AffectorExclude.h | 44 + .../shared/generator/AffectorFloraDynamic.cpp | 383 +++ .../shared/generator/AffectorFloraDynamic.h | 170 ++ .../shared/generator/AffectorFloraStatic.cpp | 431 +++ .../shared/generator/AffectorFloraStatic.h | 171 ++ .../src/shared/generator/AffectorHeight.cpp | 731 +++++ .../src/shared/generator/AffectorHeight.h | 193 ++ .../src/shared/generator/AffectorPassable.cpp | 137 + .../src/shared/generator/AffectorPassable.h | 53 + .../src/shared/generator/AffectorRibbon.cpp | 749 ++++++ .../src/shared/generator/AffectorRibbon.h | 182 ++ .../src/shared/generator/AffectorRiver.cpp | 940 +++++++ .../src/shared/generator/AffectorRiver.h | 185 ++ .../src/shared/generator/AffectorRoad.cpp | 745 ++++++ .../src/shared/generator/AffectorRoad.h | 120 + .../src/shared/generator/AffectorShader.cpp | 431 +++ .../src/shared/generator/AffectorShader.h | 168 ++ .../src/shared/generator/Array2d.h | 238 ++ .../src/shared/generator/BitmapGroup.cpp | 611 +++++ .../src/shared/generator/BitmapGroup.h | 78 + .../src/shared/generator/Boundary.cpp | 1903 +++++++++++++ .../src/shared/generator/Boundary.h | 378 +++ .../src/shared/generator/ColorRamp256.cpp | 126 + .../src/shared/generator/ColorRamp256.h | 91 + .../src/shared/generator/CoordinateHash.cpp | 233 ++ .../src/shared/generator/CoordinateHash.h | 29 + .../src/shared/generator/EnvironmentGroup.cpp | 635 +++++ .../src/shared/generator/EnvironmentGroup.h | 115 + .../src/shared/generator/FastKeyList.h | 133 + .../src/shared/generator/FastList.h | 125 + .../src/shared/generator/Feather.h | 112 + .../src/shared/generator/Filter.cpp | 1298 +++++++++ .../src/shared/generator/Filter.h | 392 +++ .../src/shared/generator/FloraGroup.cpp | 1458 ++++++++++ .../src/shared/generator/FloraGroup.h | 167 ++ .../src/shared/generator/FractalGroup.cpp | 478 ++++ .../src/shared/generator/FractalGroup.h | 81 + .../src/shared/generator/HeightData.cpp | 488 ++++ .../src/shared/generator/HeightData.h | 71 + .../src/shared/generator/RadialGroup.cpp | 1208 +++++++++ .../src/shared/generator/RadialGroup.h | 154 ++ .../src/shared/generator/ShaderGroup.cpp | 1473 ++++++++++ .../src/shared/generator/ShaderGroup.h | 172 ++ .../src/shared/generator/TerrainGenerator.cpp | 2381 +++++++++++++++++ .../src/shared/generator/TerrainGenerator.h | 886 ++++++ .../generator/TerrainGeneratorLoader.cpp | 496 ++++ .../shared/generator/TerrainGeneratorLoader.h | 50 + .../shared/generator/TerrainGeneratorType.def | 118 + .../shared/generator/TerrainGeneratorType.h | 72 + .../generator/TerrainModificationHelper.cpp | 110 + .../generator/TerrainModificationHelper.h | 37 + .../src/shared/object/TerrainObject.cpp | 795 ++++++ .../src/shared/object/TerrainObject.h | 165 ++ .../TerrainReferenceObjectNotification.cpp | 87 + .../TerrainReferenceObjectNotification.h | 46 + .../src/win32/FirstSharedTerrain.cpp | 8 + 159 files changed, 37404 insertions(+) create mode 100644 engine/shared/library/sharedTerrain/CMakeLists.txt create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/Affector.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorColor.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorEnvironment.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorExclude.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraDynamic.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraStatic.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorHeight.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorPassable.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRibbon.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRiver.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRoad.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorShader.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/Array2d.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/BitmapGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/Boundary.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ColorRamp256.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ConfigSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/CoordinateHash.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/EnvironmentGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastKeyList.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastList.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/Feather.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/Filter.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FirstSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraManager.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/FractalGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/HeightData.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/RadialGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance_Cache.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerFloraManager.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance_Cache.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SetupSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/ShaderGroup.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGenerator.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorLoader.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.def create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainModificationHelper.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainObject.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainQuadTree.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainReferenceObjectNotification.h create mode 100644 engine/shared/library/sharedTerrain/include/public/sharedTerrain/WaterTypeManager.h create mode 100644 engine/shared/library/sharedTerrain/src/CMakeLists.txt create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/FirstSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Affector.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Affector.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Array2d.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Boundary.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Boundary.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FastKeyList.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FastList.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Feather.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Filter.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/Filter.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/HeightData.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/HeightData.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.def create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.h create mode 100644 engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.cpp create mode 100644 engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.h create mode 100644 engine/shared/library/sharedTerrain/src/win32/FirstSharedTerrain.cpp diff --git a/engine/shared/library/CMakeLists.txt b/engine/shared/library/CMakeLists.txt index 55151ae9..9ec45bc5 100644 --- a/engine/shared/library/CMakeLists.txt +++ b/engine/shared/library/CMakeLists.txt @@ -15,5 +15,6 @@ add_subdirectory(sharedNetworkMessages) add_subdirectory(sharedObject) add_subdirectory(sharedRandom) add_subdirectory(sharedSynchronization) +add_subdirectory(sharedTerrain) add_subdirectory(sharedThread) add_subdirectory(sharedUtility) diff --git a/engine/shared/library/sharedTerrain/CMakeLists.txt b/engine/shared/library/sharedTerrain/CMakeLists.txt new file mode 100644 index 00000000..4690a6b4 --- /dev/null +++ b/engine/shared/library/sharedTerrain/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 2.8) + +project(sharedTerrain) + +if(WIN32) + add_definitions(/D_CRT_SECURE_NO_WARNINGS) +endif() + +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include/public) + +add_subdirectory(src) diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Affector.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Affector.h new file mode 100644 index 00000000..621a8f9d --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Affector.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/Affector.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorColor.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorColor.h new file mode 100644 index 00000000..114cf16e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorColor.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorColor.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorEnvironment.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorEnvironment.h new file mode 100644 index 00000000..505d1230 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorEnvironment.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorEnvironment.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorExclude.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorExclude.h new file mode 100644 index 00000000..f8ad0e5d --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorExclude.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorExclude.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraDynamic.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraDynamic.h new file mode 100644 index 00000000..f50ef12e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraDynamic.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorFloraDynamic.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraStatic.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraStatic.h new file mode 100644 index 00000000..c221479e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorFloraStatic.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorFloraStatic.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorHeight.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorHeight.h new file mode 100644 index 00000000..1c90ea2e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorHeight.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorHeight.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorPassable.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorPassable.h new file mode 100644 index 00000000..a93269c8 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorPassable.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorPassable.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRibbon.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRibbon.h new file mode 100644 index 00000000..ccc5ef12 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRibbon.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorRibbon.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRiver.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRiver.h new file mode 100644 index 00000000..b19c42fb --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRiver.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorRiver.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRoad.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRoad.h new file mode 100644 index 00000000..d00b904e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorRoad.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorRoad.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorShader.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorShader.h new file mode 100644 index 00000000..aaa38628 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/AffectorShader.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/AffectorShader.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Array2d.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Array2d.h new file mode 100644 index 00000000..3cea4f8a --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Array2d.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/Array2d.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/BitmapGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/BitmapGroup.h new file mode 100644 index 00000000..3d6e8bdf --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/BitmapGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/BitmapGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Boundary.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Boundary.h new file mode 100644 index 00000000..b7cbf0cc --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Boundary.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/Boundary.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ColorRamp256.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ColorRamp256.h new file mode 100644 index 00000000..ba6460c1 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ColorRamp256.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/ColorRamp256.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ConfigSharedTerrain.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ConfigSharedTerrain.h new file mode 100644 index 00000000..c4fa334e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ConfigSharedTerrain.h @@ -0,0 +1 @@ +#include "../../src/shared/core/ConfigSharedTerrain.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/CoordinateHash.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/CoordinateHash.h new file mode 100644 index 00000000..da9a1bc8 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/CoordinateHash.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/CoordinateHash.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/EnvironmentGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/EnvironmentGroup.h new file mode 100644 index 00000000..84cb4918 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/EnvironmentGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/EnvironmentGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastKeyList.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastKeyList.h new file mode 100644 index 00000000..1ee25b1a --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastKeyList.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/FastKeyList.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastList.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastList.h new file mode 100644 index 00000000..255d0a86 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FastList.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/FastList.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Feather.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Feather.h new file mode 100644 index 00000000..58d1dad4 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Feather.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/Feather.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Filter.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Filter.h new file mode 100644 index 00000000..dcd8757c --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/Filter.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/Filter.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FirstSharedTerrain.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FirstSharedTerrain.h new file mode 100644 index 00000000..ecca9fba --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FirstSharedTerrain.h @@ -0,0 +1 @@ +#include "../../src/shared/core/FirstSharedTerrain.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraGroup.h new file mode 100644 index 00000000..d59161fc --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/FloraGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraManager.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraManager.h new file mode 100644 index 00000000..9f7b7c36 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FloraManager.h @@ -0,0 +1 @@ +#include "../../src/shared/flora/FloraManager.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FractalGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FractalGroup.h new file mode 100644 index 00000000..11f11f43 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/FractalGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/FractalGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/HeightData.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/HeightData.h new file mode 100644 index 00000000..c807f383 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/HeightData.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/HeightData.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearance.h new file mode 100644 index 00000000..589bd236 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ProceduralTerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearanceTemplate.h new file mode 100644 index 00000000..2c0d0ce3 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ProceduralTerrainAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ProceduralTerrainAppearanceTemplate.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/RadialGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/RadialGroup.h new file mode 100644 index 00000000..95fb2e4f --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/RadialGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/RadialGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance.h new file mode 100644 index 00000000..8ee852b9 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/SamplerProceduralTerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h new file mode 100644 index 00000000..8f678905 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance_Cache.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance_Cache.h new file mode 100644 index 00000000..370997b2 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SamplerProceduralTerrainAppearance_Cache.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerFloraManager.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerFloraManager.h new file mode 100644 index 00000000..9d963fc7 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerFloraManager.h @@ -0,0 +1 @@ +#include "../../src/shared/flora/ServerFloraManager.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance.h new file mode 100644 index 00000000..ad931e4d --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ServerProceduralTerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h new file mode 100644 index 00000000..eafa1ca4 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance_Cache.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance_Cache.h new file mode 100644 index 00000000..420dd4e0 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerProceduralTerrainAppearance_Cache.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ServerProceduralTerrainAppearance_Cache.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearance.h new file mode 100644 index 00000000..cf25657e --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ServerSpaceTerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h new file mode 100644 index 00000000..402e0383 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SetupSharedTerrain.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SetupSharedTerrain.h new file mode 100644 index 00000000..f26e91df --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SetupSharedTerrain.h @@ -0,0 +1 @@ +#include "../../src/shared/core/SetupSharedTerrain.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ShaderGroup.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ShaderGroup.h new file mode 100644 index 00000000..3f320306 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/ShaderGroup.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/ShaderGroup.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearance.h new file mode 100644 index 00000000..fcabb5b0 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/SpaceTerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearanceTemplate.h new file mode 100644 index 00000000..fe5f7096 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/SpaceTerrainAppearanceTemplate.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/SpaceTerrainAppearanceTemplate.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainAppearance.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainAppearance.h new file mode 100644 index 00000000..819b4df6 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainAppearance.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/TerrainAppearance.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGenerator.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGenerator.h new file mode 100644 index 00000000..50e8d21d --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGenerator.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/TerrainGenerator.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorLoader.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorLoader.h new file mode 100644 index 00000000..5452eee1 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorLoader.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/TerrainGeneratorLoader.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.def b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.def new file mode 100644 index 00000000..6f41878d --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.def @@ -0,0 +1 @@ +#include "../../src/shared/generator/TerrainGeneratorType.def" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.h new file mode 100644 index 00000000..ddeddcd1 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainGeneratorType.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/TerrainGeneratorType.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainModificationHelper.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainModificationHelper.h new file mode 100644 index 00000000..3d5423e1 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainModificationHelper.h @@ -0,0 +1 @@ +#include "../../src/shared/generator/TerrainModificationHelper.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainObject.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainObject.h new file mode 100644 index 00000000..671fe11f --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainObject.h @@ -0,0 +1 @@ +#include "../../src/shared/object/TerrainObject.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainQuadTree.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainQuadTree.h new file mode 100644 index 00000000..f6577189 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainQuadTree.h @@ -0,0 +1 @@ +#include "../../src/shared/appearance/TerrainQuadTree.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainReferenceObjectNotification.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainReferenceObjectNotification.h new file mode 100644 index 00000000..b4556c23 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/TerrainReferenceObjectNotification.h @@ -0,0 +1 @@ +#include "../../src/shared/object/TerrainReferenceObjectNotification.h" diff --git a/engine/shared/library/sharedTerrain/include/public/sharedTerrain/WaterTypeManager.h b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/WaterTypeManager.h new file mode 100644 index 00000000..cb5b5a34 --- /dev/null +++ b/engine/shared/library/sharedTerrain/include/public/sharedTerrain/WaterTypeManager.h @@ -0,0 +1 @@ +#include "../../src/shared/core/WaterTypeManager.h" diff --git a/engine/shared/library/sharedTerrain/src/CMakeLists.txt b/engine/shared/library/sharedTerrain/src/CMakeLists.txt new file mode 100644 index 00000000..589f5d5c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/CMakeLists.txt @@ -0,0 +1,140 @@ + +set(SHARED_SOURCES + shared/appearance/ProceduralTerrainAppearance.cpp + shared/appearance/ProceduralTerrainAppearance.h + shared/appearance/ProceduralTerrainAppearanceTemplate.cpp + shared/appearance/ProceduralTerrainAppearanceTemplate.h + shared/appearance/SamplerProceduralTerrainAppearance.cpp + shared/appearance/SamplerProceduralTerrainAppearance.h + shared/appearance/SamplerProceduralTerrainAppearance_Cache.cpp + shared/appearance/SamplerProceduralTerrainAppearance_Cache.h + shared/appearance/SamplerProceduralTerrainAppearanceTemplate.cpp + shared/appearance/SamplerProceduralTerrainAppearanceTemplate.h + shared/appearance/ServerProceduralTerrainAppearance_Cache.cpp + shared/appearance/ServerProceduralTerrainAppearance_Cache.h + shared/appearance/ServerProceduralTerrainAppearance.cpp + shared/appearance/ServerProceduralTerrainAppearance.h + shared/appearance/ServerProceduralTerrainAppearanceTemplate.cpp + shared/appearance/ServerProceduralTerrainAppearanceTemplate.h + shared/appearance/ServerSpaceTerrainAppearance.cpp + shared/appearance/ServerSpaceTerrainAppearance.h + shared/appearance/ServerSpaceTerrainAppearanceTemplate.cpp + shared/appearance/ServerSpaceTerrainAppearanceTemplate.h + shared/appearance/SpaceTerrainAppearance.cpp + shared/appearance/SpaceTerrainAppearance.h + shared/appearance/SpaceTerrainAppearanceTemplate.cpp + shared/appearance/SpaceTerrainAppearanceTemplate.h + shared/appearance/TerrainAppearance.cpp + shared/appearance/TerrainAppearance.h + shared/appearance/TerrainQuadTree.cpp + shared/appearance/TerrainQuadTree.h + + shared/core/ConfigSharedTerrain.cpp + shared/core/ConfigSharedTerrain.h + shared/core/FirstSharedTerrain.h + shared/core/SetupSharedTerrain.cpp + shared/core/SetupSharedTerrain.h + shared/core/WaterTypeManager.cpp + shared/core/WaterTypeManager.h + + shared/flora/FloraManager.cpp + shared/flora/FloraManager.h + shared/flora/ServerFloraManager.cpp + shared/flora/ServerFloraManager.h + + shared/generator/AffectorColor.cpp + shared/generator/AffectorColor.h + shared/generator/Affector.cpp + shared/generator/AffectorEnvironment.cpp + shared/generator/AffectorEnvironment.h + shared/generator/AffectorExclude.cpp + shared/generator/AffectorExclude.h + shared/generator/AffectorFloraDynamic.cpp + shared/generator/AffectorFloraDynamic.h + shared/generator/AffectorFloraStatic.cpp + shared/generator/AffectorFloraStatic.h + shared/generator/Affector.h + shared/generator/AffectorHeight.cpp + shared/generator/AffectorHeight.h + shared/generator/AffectorPassable.cpp + shared/generator/AffectorPassable.h + shared/generator/AffectorRibbon.cpp + shared/generator/AffectorRibbon.h + shared/generator/AffectorRiver.cpp + shared/generator/AffectorRiver.h + shared/generator/AffectorRoad.cpp + shared/generator/AffectorRoad.h + shared/generator/AffectorShader.cpp + shared/generator/AffectorShader.h + shared/generator/Array2d.h + shared/generator/BitmapGroup.cpp + shared/generator/BitmapGroup.h + shared/generator/Boundary.cpp + shared/generator/Boundary.h + shared/generator/ColorRamp256.cpp + shared/generator/ColorRamp256.h + shared/generator/CoordinateHash.cpp + shared/generator/CoordinateHash.h + shared/generator/EnvironmentGroup.cpp + shared/generator/EnvironmentGroup.h + shared/generator/FastKeyList.h + shared/generator/FastList.h + shared/generator/Feather.h + shared/generator/Filter.cpp + shared/generator/Filter.h + shared/generator/FloraGroup.cpp + shared/generator/FloraGroup.h + shared/generator/FractalGroup.cpp + shared/generator/FractalGroup.h + shared/generator/HeightData.cpp + shared/generator/HeightData.h + shared/generator/RadialGroup.cpp + shared/generator/RadialGroup.h + shared/generator/ShaderGroup.cpp + shared/generator/ShaderGroup.h + shared/generator/TerrainGenerator.cpp + shared/generator/TerrainGenerator.h + shared/generator/TerrainGeneratorLoader.cpp + shared/generator/TerrainGeneratorLoader.h + shared/generator/TerrainGeneratorType.def + shared/generator/TerrainGeneratorType.h + shared/generator/TerrainModificationHelper.cpp + shared/generator/TerrainModificationHelper.h + + shared/object/TerrainObject.cpp + shared/object/TerrainObject.h + shared/object/TerrainReferenceObjectNotification.cpp + shared/object/TerrainReferenceObjectNotification.h +) + +if(WIN32) + set(PLATFORM_SOURCES + win32/FirstSharedTerrain.cpp + ) + + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/win32) +else() + set(PLATFORM_SOURCES "") +endif() + +include_directories( + ${CMAKE_CURRENT_SOURCE_DIR}/shared + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedCollision/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedDebug/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFile/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundation/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFoundationTypes/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedFractal/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedImage/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMath/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedMemoryManager/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedObject/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedRandom/include/public + ${SWG_ENGINE_SOURCE_DIR}/shared/library/sharedUtility/include/public + ${SWG_EXTERNALS_SOURCE_DIR}/ours/library/fileInterface/include/public +) + +add_library(sharedTerrain STATIC + ${SHARED_SOURCES} + ${PLATFORM_SOURCES} +) diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.cpp new file mode 100644 index 00000000..e116cba9 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.cpp @@ -0,0 +1,1547 @@ +//=================================================================== +// +// ProceduralTerrainAppearance.cpp +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" + +#include "sharedCollision/BoxExtent.h" +#include "sharedCollision/CollisionInfo.h" +#include "sharedCollision/CollisionProperty.h" +#include "sharedCollision/ExtentList.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedFoundation/CrcLowerString.h" +#include "sharedFoundation/ExitChain.h" +#ifndef WIN32 +#include "sharedLog/Log.h" // for LOG() +#endif +#include "sharedObject/AlterResult.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedObject/World.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "sharedTerrain/ProceduralTerrainAppearanceTemplate.h" +#include "sharedTerrain/TerrainObject.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedUtility/BakedTerrain.h" +#include "sharedUtility/FileName.h" +#include "sharedRandom/RandomGenerator.h" +#include "sharedRandom/FastRandomGenerator.h" + +#include +#include + +#include + +#ifndef WIN32 +#include // for LOG() +#endif + +#define FLORA_ALLOWED_DISTANCE (8.0f) + +namespace +{ + bool ms_logFloraCreation; + bool ms_logGetHeightFailures; + int ms_maximumNumberOfChunksAllowed; +} + +//=================================================================== +// +// ProceduralTerrainAppearance::CreateChunkData +// + +ProceduralTerrainAppearance::CreateChunkData::CreateChunkData (TerrainGenerator::CreateChunkBuffer* newCreateChunkBuffer) : + createChunkBuffer (newCreateChunkBuffer), + chunkX (0), + chunkZ (0), + numberOfTilesPerChunk (0), + chunkWidthInMeters (0), + tileWidthInMeters (0), + start (), + originOffset(0), + numberOfPoles(0), + shaderGroup (0), + floraGroup (0), + radialGroup (0), + environmentGroup (0), + fractalGroup (0), + bitmapGroup (0) +{ + hasLargerNeighborFlags=0; +} + +//------------------------------------------------------------------- + +ProceduralTerrainAppearance::CreateChunkData::~CreateChunkData () +{ + createChunkBuffer = 0; + + floraGroup = 0; + shaderGroup = 0; + radialGroup = 0; + environmentGroup = 0; + fractalGroup = 0; + bitmapGroup = 0; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::CreateChunkData::validate () const +{ + NOT_NULL (createChunkBuffer); + createChunkBuffer->validate (); + + DEBUG_FATAL (numberOfTilesPerChunk == 0, ("ProceduralTerrainAppearance::CreateChunkData::validate - numberOfTilesPerChunk == 0")); + DEBUG_FATAL (chunkWidthInMeters == 0, ("ProceduralTerrainAppearance::CreateChunkData::validate - chunkWidthInMeters == 0")); +// DEBUG_FATAL (tileWidthInMeters == 0, ("ProceduralTerrainAppearance::CreateChunkData::validate - tileWidthInMeters == 0")); + DEBUG_FATAL (numberOfPoles == 0, ("ProceduralTerrainAppearance::CreateChunkData::validate - numberOfPoles == 0")); + NOT_NULL (shaderGroup); + NOT_NULL (floraGroup); + NOT_NULL (radialGroup); + NOT_NULL (environmentGroup); + NOT_NULL (fractalGroup); + NOT_NULL (bitmapGroup); +} + +//=================================================================== +// +// ProceduralTerrainAppearance::SurfaceData +// +ProceduralTerrainAppearance::SurfaceData::SurfaceData () : + objectTemplate (0) +{ +} + +//=================================================================== +// +// ProceduralTerrainAppearance::StaticFloraData +// +ProceduralTerrainAppearance::StaticFloraData::StaticFloraData () : + floats (false), + childChoice (0.f), + familyChildData () +{ +} + +//=================================================================== +// +// ProceduralTerrainAppearance::Chunk +// +bool ProceduralTerrainAppearance::Chunk::ms_drawVertexNormals; +bool ProceduralTerrainAppearance::Chunk::ms_drawExtent; + +//------------------------------------------------------------------- + +ProceduralTerrainAppearance::Chunk::Chunk (ProceduralTerrainAppearance& proceduralTerrainAppearance) : + Appearance (0), + m_proceduralTerrainAppearance(proceduralTerrainAppearance), + chunkX (0), + chunkZ (0), + chunkWidthInMeters (0), + originOffset(0), + numberOfPoles(0), + m_boxExtent(), + shaderMap (0), + m_floraStaticCollidableMap (0), + m_excluded(0), + m_passable(unsigned(-1)), + m_spatialSubdivisionHandle (0) +{ + hasLargerNeighborFlags=0; + + m_extent=&m_boxExtent; +} + +//------------------------------------------------------------------- + +ProceduralTerrainAppearance::Chunk::~Chunk () +{ + _prepareForDelete (); + + DEBUG_FATAL(m_extent!=&m_boxExtent, ("extent illegally set on ProceduralTerrainAppearance::Chunk")); + m_extent =0; + shaderMap = 0; + m_floraStaticCollidableMap = 0; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::_prepareForDelete () +{ + m_proceduralTerrainAppearance.prepareForDelete(this); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::_setExcluded(int const tileX, int const tileZ) +{ + int const tileIndex = tileZ * m_proceduralTerrainAppearance.getNumberOfTilesPerChunk() + tileX; + m_excluded |= (1 << tileIndex); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::isExcluded(const Vector& position) const +{ + int tileX, tileZ; + _findTileXz(position, tileX, tileZ); + int const tileIndex = tileZ * m_proceduralTerrainAppearance.getNumberOfTilesPerChunk() + tileX; + return (m_excluded & (1 << tileIndex)) != 0; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::isExcluded(int const tileX, int const tileZ) const +{ + int const tileIndex = tileZ * m_proceduralTerrainAppearance.getNumberOfTilesPerChunk() + tileX; + return (m_excluded & (1 << tileIndex)) != 0; +} + +//------------------------------------------------------------------- + +int ProceduralTerrainAppearance::Chunk::getChunkMemorySize () const +{ + NOT_NULL (shaderMap); + const int shaderMapSize = isizeof (ShaderGroup::Info) * shaderMap->getWidth () * shaderMap->getHeight (); + + int floraMapSize=0; + if (m_floraStaticCollidableMap) + { + floraMapSize = isizeof (FloraGroup::Info) * m_floraStaticCollidableMap->getWidth () * m_floraStaticCollidableMap->getHeight (); + } + +#ifdef _DEBUG + DEBUG_REPORT_PRINT (true, (" shaderMapSize = %i\n", shaderMapSize)); + DEBUG_REPORT_PRINT (true, (" floraMapSize = %i\n", floraMapSize)); +#endif + + return isizeof (*this) + shaderMapSize + floraMapSize; +} + +//------------------------------------------------------------------- + +#ifdef _DEBUG + +bool ProceduralTerrainAppearance::Chunk::debugRenderingEnabled () const +{ + return false; +} + +#endif + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::setDrawVertexNormals (bool drawVertexNormals) +{ + ms_drawVertexNormals = drawVertexNormals; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::getDrawVertexNormals () +{ + return ms_drawVertexNormals; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::setDrawExtent (bool drawExtent) +{ + ms_drawExtent = drawExtent; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::getDrawExtent () +{ + return ms_drawExtent; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::_findMapXz(const Vector& position, int &mapX, int &mapZ) const +{ + const float chunk2Meters = m_proceduralTerrainAppearance.getChunkWidthInMeters(); + const float minX = float(chunkX) * chunk2Meters; + const float minZ = float(chunkZ) * chunk2Meters; + const float ratioX = clamp (0.f, (position.x - minX) / chunkWidthInMeters, 1.f); + const float ratioZ = clamp (0.f, (position.z - minZ) / chunkWidthInMeters, 1.f); + const int numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + mapX = originOffset + static_cast(ratioX * float(numberOfTilesPerChunk * 2)); //lint !e790 //-- integral to float + mapZ = originOffset + static_cast(ratioZ * float(numberOfTilesPerChunk * 2)); //lint !e790 //-- integral to float +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::setPassable(int const tileX, int const tileZ, bool isPassable) +{ + int const tileIndex = tileZ * m_proceduralTerrainAppearance.getNumberOfTilesPerChunk() + tileX; + if (isPassable) + { + m_passable |= (1 << tileIndex); + } + else + { + m_passable &= ~(1 << tileIndex); + } +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::isPassable(const Vector& position) const +{ + int tileX, tileZ; + _findTileXz(position, tileX, tileZ); + int const tileIndex = tileZ * m_proceduralTerrainAppearance.getNumberOfTilesPerChunk() + tileX; + return (m_passable & (1 << tileIndex)) != 0; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::_findTileXz(Vector const & position, int & tileX, int & tileZ) const +{ + const float chunk2Meters = m_proceduralTerrainAppearance.getChunkWidthInMeters(); + const float minX = float(chunkX) * chunk2Meters; + const float minZ = float(chunkZ) * chunk2Meters; + + const int numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + const float tileWidthInMeters = chunkWidthInMeters / numberOfTilesPerChunk; + + tileX = clamp(0, static_cast((position.x - minX) / tileWidthInMeters), numberOfTilesPerChunk - 1); + tileZ = clamp(0, static_cast((position.z - minZ) / tileWidthInMeters), numberOfTilesPerChunk - 1); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::findSurface (const Vector& position, SurfaceData& data) const +{ + int tileX; + int tileZ; + _findTileXz(position, tileX, tileZ); + if (isExcluded(tileX, tileZ)) + return false; + + int x; + int z; + _findMapXz (position, x, z); + + NOT_NULL (shaderMap); + const ShaderGroup::Info sgi = shaderMap->getData (x, z); + + if (sgi.getFamilyId ()) + { + ShaderGroup const & shaderGroup = m_proceduralTerrainAppearance.getShaderGroup(); + data.objectTemplate = shaderGroup.getFamilySurfaceProperties(sgi.getFamilyId()); + + return true; + } + + return false; +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::Chunk::_makeStaticFloraData(StaticFloraData& o_data, const FloraGroup::Info &i_groupInfo) const +{ + FloraGroup const & floraGroup = m_proceduralTerrainAppearance.getFloraGroup(); + //-- family data + o_data.floats = floraGroup.getFamilyFloats(i_groupInfo.getFamilyId()); + o_data.childChoice = i_groupInfo.getChildChoice (); + + //-- family child data + o_data.familyChildData = &floraGroup.createFlora(i_groupInfo); +} + +//----------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::_floraAllowed(float positionX, float positionZ) const +{ + if (chunkWidthInMeters <= FLORA_ALLOWED_DISTANCE) + { + const Vector pos3(positionX, 0, positionZ); + + int tileX, tileZ; + _findTileXz(pos3, tileX, tileZ); + if (isExcluded(tileX, tileZ)) + { + return false; + } + + return true; + } + + return false; +} + +//----------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::_findStaticFlora(const Array2d& floraMap, const float positionX, const float positionZ, StaticFloraData& data, bool& floraAllowed) const +{ + FloraGroup::Info groupInfo; + if (_findStaticFlora(floraMap, positionX, positionZ, groupInfo, floraAllowed)) + { + _makeStaticFloraData(data, groupInfo); + return true; + } + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::Chunk::_findStaticFlora(const Array2d& floraMap, float positionX, float positionZ, FloraGroup::Info &data, bool& floraAllowed) const +{ + if (chunkWidthInMeters <= FLORA_ALLOWED_DISTANCE) + { + const Vector pos3(positionX, 0, positionZ); + + int tileX, tileZ; + _findTileXz(pos3, tileX, tileZ); + if (isExcluded(tileX, tileZ)) + { + return false; + } + + floraAllowed = true; + + int x, z; + _findMapXz (pos3, x, z); + + data = floraMap.getData (x, z); + return (data.getFamilyId()) ? true : false; + } + + return false; +} + +//=================================================================== +// STATIC PUBLIC ProceduralTerrainAppearance +//=================================================================== + +ProceduralTerrainAppearance::CreateFloraHookFunction ProceduralTerrainAppearance::ms_createFloraHookFunction = 0; + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::install () +{ + DebugFlags::registerFlag (ms_logFloraCreation, "SharedTerrain", "logFloraCreation"); + DebugFlags::registerFlag (ms_logGetHeightFailures, "SharedTerrain", "logGetHeightFailures"); + + ms_maximumNumberOfChunksAllowed = ConfigSharedTerrain::getMaximumNumberOfChunksAllowed (); + + ExitChain::add (remove, "ProceduralTerrainAppearance::remove"); +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::remove () +{ + DebugFlags::unregisterFlag (ms_logFloraCreation); + DebugFlags::unregisterFlag (ms_logGetHeightFailures); +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::setCreateFloraHookFunction (ProceduralTerrainAppearance::CreateFloraHookFunction createFloraHookFunction) +{ + ms_createFloraHookFunction = createFloraHookFunction; +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::setMaximumNumberOfChunksAllowed (int newMaximumNumberOfChunksAllowed) +{ + ms_maximumNumberOfChunksAllowed = newMaximumNumberOfChunksAllowed; +} + +//=================================================================== +// PUBLIC ProceduralTerrainAppearance +//=================================================================== + +ProceduralTerrainAppearance::ProceduralTerrainAppearance (const ProceduralTerrainAppearanceTemplate* appearanceTemplate) : + TerrainAppearance (NON_NULL (appearanceTemplate)), + originOffset(appearanceTemplate->getChunkOriginOffset()), + upperPad(appearanceTemplate->getChunkUpperPad()), + numberOfPoles(2*appearanceTemplate->getNumberOfTilesPerChunk() + originOffset + upperPad), + sphere (), + createChunkBuffer (), + generateHeightChunkBuffer (), + maximumNumberOfChunksAllowed (0), + maximumNumberOfChunksAlongSide (0), + proceduralTerrainAppearanceTemplate (appearanceTemplate), + m_runTimeRuleList (new RunTimeRuleList), + m_chunksGeneratedThisFrame (0), + m_server (false), + m_floraMap (new FloraMap), + m_cachedFloraMap (new FloraMap), + m_clearCollidableFloraMap (new ClearCollidableFloraMap), + m_hasPassableAffectors(false) +{ + const TerrainGenerator* terrainGenerator = proceduralTerrainAppearanceTemplate->getTerrainGenerator (); + const float mapWidthInMeters = proceduralTerrainAppearanceTemplate->getMapWidthInMeters (); + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + sphere.setRadius (2048.f); + + //-- make sure our generator was loaded + NOT_NULL (terrainGenerator); + + //-- setup scratch buffer + createChunkBuffer.allocate (numberOfPoles); + + const int generateHeightPoles = 2*1 + originOffset + upperPad; + + generateHeightChunkBuffer.allocate(generateHeightPoles); + + //-- allocate caches + const_cast (terrainGenerator)->getFractalGroup ().prepare (numberOfPoles, numberOfPoles); + + // + //-- calculate max chunks + // + + //-- + maximumNumberOfChunksAllowed = ms_maximumNumberOfChunksAllowed; + maximumNumberOfChunksAlongSide = static_cast (mapWidthInMeters / ( 2 * chunkWidthInMeters)); + + m_hasPassableAffectors = terrainGenerator->hasPassableAffectors(); +} + +//------------------------------------------------------------------- + +ProceduralTerrainAppearance::~ProceduralTerrainAppearance () +{ + //-- delete clear flora map + DEBUG_WARNING (!m_clearCollidableFloraMap->empty (), ("ProceduralTerrainAppearance: %u clear flora objects leaked\n", m_clearCollidableFloraMap->size ())); + delete m_clearCollidableFloraMap; + + //-- delete flora + DEBUG_WARNING (!m_floraMap->empty (), ("ProceduralTerrainAppearance: %u flora objects leaked\n", m_floraMap->size ())); + + while (!m_floraMap->empty ()) + { + Object* const object = NON_NULL (m_floraMap->begin ()->second); + DEBUG_WARNING (object->getAppearance () && object->getAppearance ()->getAppearanceTemplate () && object->getAppearance ()->getAppearanceTemplate ()->getName (), ("-- [%s]\n", object->getAppearance ()->getAppearanceTemplate ()->getName ())); + object->removeFromWorld (); + delete object; + + m_floraMap->erase (m_floraMap->begin ()); + } + + delete m_floraMap; + + //-- delete cached flora map + while (!m_cachedFloraMap->empty ()) + { + Object* const object = NON_NULL (m_cachedFloraMap->begin ()->second); + delete object; + + m_cachedFloraMap->erase (m_cachedFloraMap->begin ()); + } + + delete m_cachedFloraMap; + + //-- + proceduralTerrainAppearanceTemplate = 0; + + delete m_runTimeRuleList; + m_runTimeRuleList = 0; +} + +//------------------------------------------------------------------- +/** +* Tests to see if the chunk indices fall within the map, and if the chunk creation +* clip is enabled, the indices are tested against the specified clip (initially 0,0x0,0) +* +* @see #getChunkCreationClipEnabled () +* @see #setChunkCreationClipEnabled (bool) +* @see $setChunkCreationClip (const Vector , const Vector &); +* +* @param x the x coordinate in chunk-space +* @param z the z coordinate in chunk-space +* +*/ + +bool ProceduralTerrainAppearance::areValidChunkIndices (const int x, const int z) const +{ + return (x >= -maximumNumberOfChunksAlongSide && + z >= -maximumNumberOfChunksAlongSide && + x < maximumNumberOfChunksAlongSide && + z < maximumNumberOfChunksAlongSide); +} + +//------------------------------------------------------------------- + +int ProceduralTerrainAppearance::calculateChunkX (float positionX) const +{ + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + const int chunkX = static_cast ((positionX >= 0.f) ? floorf (positionX / chunkWidthInMeters) : ceilf (positionX / chunkWidthInMeters)); + + //-- zero is not a valid chunk index + return (positionX < 0.f) ? chunkX - 1 : chunkX; +} + +//------------------------------------------------------------------- + +int ProceduralTerrainAppearance::calculateChunkZ (float positionZ) const +{ + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + const int chunkZ = static_cast ((positionZ >= 0.f) ? floorf (positionZ / chunkWidthInMeters) : ceilf (positionZ / chunkWidthInMeters)); + + //-- zero is not a valid chunk index + return (positionZ < 0.f) ? chunkZ - 1 : chunkZ; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::getChunkHeight (const int chunkX, const int chunkZ) const +{ + const Chunk* chunk = findChunk (chunkX, chunkZ, 1); + + return chunk ? chunk->getBoxExtent ().getHeight () : 0.f; +} + +//------------------------------------------------------------------- + +const BoxExtent* ProceduralTerrainAppearance::getChunkExtent (const Vector& position_o) const +{ + const Chunk* const chunk = findFirstRenderableChunk (position_o); + + return chunk ? &chunk->getBoxExtent () : 0; +} + +//------------------------------------------------------------------- + +const BoxExtent* ProceduralTerrainAppearance::getChunkExtentForceChunkCreation (const Vector& position_o) const +{ + const Chunk* chunk = findChunk (position_o, 1); + + if (!chunk) + { + DEBUG_REPORT_LOG (ms_logGetHeightFailures, ("getChunkExtentForceChunkCreation: chunk for <%1.2f, %1.2f> does not exist, creating\n", position_o.x, position_o.z)); + const_cast (this)->createChunk (position_o, 1); + + chunk = findChunk (position_o, 1); + DEBUG_REPORT_LOG (ms_logGetHeightFailures && !chunk, ("getChunkExtentForceChunkCreation: chunk for <%1.2f, %1.2f> STILL does not exist\n", position_o.x, position_o.z)); + } + + return chunk ? &chunk->getBoxExtent () : 0; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::createChunk (const Vector& position, const int chunkSize) +{ + //-- are we over our limit? + const int maximumNumberOfChunks = std::max (maximumNumberOfChunksAllowed, getNumberOfReferenceObjects () + 10); + + while (getNumberOfChunks () > maximumNumberOfChunks) + removeUnnecessaryChunk (); + + //-- where is this position in the world in reference to the terrain? + const int chunkX = calculateChunkX(position.x); + const int chunkZ = calculateChunkZ(position.z); + + if (m_server) + { + for (int j = chunkZ - 1; j <= chunkZ + 1; ++j) + for (int i = chunkX - 1; i <= chunkX + 1; ++i) + createChunk (i, j, chunkSize, 0); + } + else + createChunk (chunkX, chunkZ, chunkSize, 0); +} + +//------------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified position +*/ +const ProceduralTerrainAppearance::Chunk* ProceduralTerrainAppearance::findFirstRenderableChunk (const Vector& position) const +{ + const int chunkX = calculateChunkX (position.x); + const int chunkZ = calculateChunkZ (position.z); + + return findFirstRenderableChunk (chunkX, chunkZ); +} + +//------------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified X,Z coordinates +*/ +const ProceduralTerrainAppearance::Chunk* ProceduralTerrainAppearance::findFirstRenderableChunk2D(float positionX, float positionZ) const +{ + const int chunkX = calculateChunkX(positionX); + const int chunkZ = calculateChunkZ(positionZ); + + return findFirstRenderableChunk (chunkX, chunkZ); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* ProceduralTerrainAppearance::findChunk (const Vector& position, const int chunkSize) const +{ + //-- where is this position in the world in reference to the terrain? + const int chunkX = calculateChunkX (position.x); + const int chunkZ = calculateChunkZ (position.z); + + return findChunk (chunkX, chunkZ, chunkSize); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* ProceduralTerrainAppearance::findAnyChunk () const +{ + return 0; +} + +//------------------------------------------------------------------- + +const Sphere& ProceduralTerrainAppearance::getSphere () const +{ + return sphere; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getHeight (const Vector& position_o, float& height) const +{ + if (ConfigSharedTerrain::getDisableGetHeight ()) + { + height = 0.f; + return true; + } + + const Chunk* chunk = findFirstRenderableChunk (position_o); + + if (chunk && chunk->getHeightAt (position_o, &height)) + return true; + + // DEBUG_WARNING (true, ("ProceduralTerrainAppearance::getHeight - could not find height for position <%1.2f, %1.2f>", position_o.x, position_o.z)); + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getHeight (const Vector& position_o, float& height, Vector& normal) const +{ + if (ConfigSharedTerrain::getDisableGetHeight ()) + { + height = 0.f; + normal = Vector::unitY; + + return true; + } + + const Chunk* chunk = findFirstRenderableChunk (position_o); + + if (chunk && chunk->getHeightAt (position_o, &height, &normal)) + return true; + + DEBUG_REPORT_LOG (ms_logGetHeightFailures, ("getHeight: could not find height for position <%1.2f, %1.2f>\n", position_o.x, position_o.z)); + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getHeightForceChunkCreation (const Vector& position_o, float& height) const +{ + const Chunk* chunk = findChunk (position_o, 1); + + if (!chunk) + { + DEBUG_REPORT_LOG (ms_logGetHeightFailures, ("getHeightForceChunkCreation: chunk for <%1.2f, %1.2f> does not exist, creating\n", position_o.x, position_o.z)); + const_cast (this)->createChunk (position_o, 1); + + chunk = findChunk (position_o, 1); + DEBUG_REPORT_LOG (ms_logGetHeightFailures && !chunk, ("getHeightForceChunkCreation: chunk for <%1.2f, %1.2f> STILL does not exist\n", position_o.x, position_o.z)); + } + + return chunk && chunk->getHeightAt (position_o, &height); +} + +//------------------------------------------------------------------- + +const ObjectTemplate* ProceduralTerrainAppearance::getSurfaceProperties (const Vector& position_o) const +{ + SurfaceData sd; + if (findSurface (position_o, sd)) + return sd.objectTemplate; + + return 0; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getWaterHeight (const Vector& position_o, float& height) const +{ + return proceduralTerrainAppearanceTemplate->getWaterHeight (position_o, height); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getWaterHeight (const Vector& position_o, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater) const +{ + return proceduralTerrainAppearanceTemplate->getWaterHeight (position_o, height, waterType, ignoreNonTransparentWater); +} + +//------------------------------------------------------------------- + +TerrainGeneratorWaterType ProceduralTerrainAppearance::getWaterType (const Vector& position_o) const +{ + return proceduralTerrainAppearanceTemplate->getWaterType (position_o); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getWater (const int chunkX, const int chunkZ) const +{ + if (proceduralTerrainAppearanceTemplate->getBakedTerrain () != NULL) + return proceduralTerrainAppearanceTemplate->getBakedTerrain ()->getWater (chunkX, chunkZ); + + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getSlope (const int chunkX, const int chunkZ) const +{ + if (proceduralTerrainAppearanceTemplate->getBakedTerrain () != NULL) + return proceduralTerrainAppearanceTemplate->getBakedTerrain ()->getSlope (chunkX, chunkZ); + + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getWater (const Rectangle2d& rectangle) const +{ + if (proceduralTerrainAppearanceTemplate->getBakedTerrain () != NULL) + return proceduralTerrainAppearanceTemplate->getBakedTerrain ()->getWater (rectangle); + + return false; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::getSlope (const Rectangle2d& rectangle) const +{ + if (proceduralTerrainAppearanceTemplate->getBakedTerrain () != NULL) + return proceduralTerrainAppearanceTemplate->getBakedTerrain ()->getSlope (rectangle); + + return false; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::getChunkWidthInMeters () const +{ + return proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::getMapWidthInMeters () const +{ + return proceduralTerrainAppearanceTemplate->getMapWidthInMeters (); +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::getEnvironmentCycleTime () const +{ + return proceduralTerrainAppearanceTemplate->getEnvironmentCycleTime (); +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::alter (float elapsedTime) +{ + PROFILER_AUTO_BLOCK_DEFINE("ProceduralTerrainAppearance::alter"); + IGNORE_RETURN (TerrainAppearance::alter (elapsedTime)); + + //-- clear cached flora list if over 256 items + int numberOfFloraToDelete = ConfigSharedTerrain::getDisableFloraCaching () ? static_cast (m_cachedFloraMap->size ()) : static_cast (m_cachedFloraMap->size ()) - 256; + while (numberOfFloraToDelete-- > 0) + { + const Object* const object = m_cachedFloraMap->begin ()->second; + if (object) + { +#ifdef _DEBUG + const char* const appearanceTemplateName = object->getAppearance () && object->getAppearance ()->getAppearanceTemplate () ? object->getAppearance ()->getAppearanceTemplate ()->getCrcName ().getString () : 0; + const Vector position = object->getPosition_w (); + DEBUG_REPORT_LOG (ms_logFloraCreation, ("flora delete: <%1.2f, %1.2f> [%s]\n", position.x, position.z, appearanceTemplateName ? appearanceTemplateName : "null")); +#endif + delete object; + } + + + m_cachedFloraMap->erase (m_cachedFloraMap->begin ()); + } + + // @todo figure out what this should return. + return AlterResult::cms_alterNextFrame; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::verifyChunk (const Chunk* chunk) const +{ + NOT_NULL (chunk); + +#ifdef _DEBUG + //-- make sure chunk extents are correct + const BoxExtent& boxExtent = chunk->getBoxExtent (); + DEBUG_WARNING (!WithinEpsilonInclusive (boxExtent.getWidth (), getChunkWidthInMeters (), 0.001f), ("extent/chunk <%i, %i> width mismatch [%1.2f/%1.2f]", chunk->getChunkX (), chunk->getChunkZ (), boxExtent.getWidth (), getChunkWidthInMeters ())); + DEBUG_WARNING (!WithinEpsilonInclusive (boxExtent.getLength (), getChunkWidthInMeters (), 0.001f), ("extent/chunk <%i, %i> length mismatch [%1.2f/%1.2f]", chunk->getChunkX (), chunk->getChunkZ (), boxExtent.getLength (), getChunkWidthInMeters ())); +#endif +} + +//------------------------------------------------------------------- + +int ProceduralTerrainAppearance::getNumberOfTilesPerChunk () const +{ + return proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk (); +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::setClient () +{ + m_server = false; +} + +//----------------------------------------------------------------- + +const ProceduralTerrainAppearance::ClearCollidableFloraMap* ProceduralTerrainAppearance::getClearCollidableFloraMap () const +{ + return m_clearCollidableFloraMap; +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearance::addLayer (const TerrainGenerator::Layer* layer) +{ + TerrainGenerator* const generator = const_cast (proceduralTerrainAppearanceTemplate->getTerrainGenerator ()); + + generator->addLayer (const_cast (layer)); + +#ifdef _DEBUG + RunTimeRuleList::const_iterator i = std::find (m_runTimeRuleList->begin (), m_runTimeRuleList->end (), layer); + DEBUG_WARNING (i != m_runTimeRuleList->end (), ("adding same run-time rule %s twice", layer->getName ())); +#endif + + m_runTimeRuleList->push_back (const_cast (layer)); +} //lint !e1762 // function could be made const + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::removeLayer (const TerrainGenerator::Layer* layer) +{ + TerrainGenerator* const generator = const_cast (proceduralTerrainAppearanceTemplate->getTerrainGenerator ()); + + generator->removeLayer (const_cast (layer), false); + + RunTimeRuleList::iterator i = std::find (m_runTimeRuleList->begin (), m_runTimeRuleList->end (), layer); + if (i != m_runTimeRuleList->end ()) + IGNORE_RETURN (m_runTimeRuleList->erase (i)); + else + DEBUG_WARNING (true, ("run-time rule %s not found", layer->getName ())); +} //lint !e1762 // function could be made const + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::prepareGenerator () +{ + TerrainGenerator* const generator = const_cast (proceduralTerrainAppearanceTemplate->getTerrainGenerator ()); + + generator->prepare (); +} //lint !e1762 // function could be made const + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearance::generateHeight_expensive (const Vector2d& position_w) +{ + const TerrainGenerator* terrainGenerator = proceduralTerrainAppearanceTemplate->getTerrainGenerator (); + const int numberOfTilesPerChunk = 1; + const float tileWidthInMeters = proceduralTerrainAppearanceTemplate->getTileWidthInMeters (); + + //-- chunk does not exist -- it needs to be created. find out what map data i'll need to ask the generator for + + const int generateHeightPoles = 2*numberOfTilesPerChunk + originOffset + upperPad; + const float distanceBetweenPoles = tileWidthInMeters * 0.5f; + + const Vector start ( + position_w.x - static_cast(originOffset) * distanceBetweenPoles, + 0.0f, + position_w.y - static_cast(originOffset) * distanceBetweenPoles) + ; + + //-- ask the generator to fill out this area + TerrainGenerator::GeneratorChunkData generatorChunkData(proceduralTerrainAppearanceTemplate->getLegacyMode()); + + generatorChunkData.heightMap = &generateHeightChunkBuffer.heightMap; + generatorChunkData.colorMap = &generateHeightChunkBuffer.colorMap; + generatorChunkData.shaderMap = &generateHeightChunkBuffer.shaderMap; + generatorChunkData.floraStaticCollidableMap = &generateHeightChunkBuffer.floraStaticCollidableMap; + generatorChunkData.floraStaticNonCollidableMap = &generateHeightChunkBuffer.floraStaticNonCollidableMap; + generatorChunkData.floraDynamicNearMap = &generateHeightChunkBuffer.floraDynamicNearMap; + generatorChunkData.floraDynamicFarMap = &generateHeightChunkBuffer.floraDynamicFarMap; + generatorChunkData.environmentMap = &generateHeightChunkBuffer.environmentMap; + generatorChunkData.vertexPositionMap = &generateHeightChunkBuffer.vertexPositionMap; + generatorChunkData.vertexNormalMap = &generateHeightChunkBuffer.vertexNormalMap; + generatorChunkData.excludeMap = &generateHeightChunkBuffer.excludeMap; + generatorChunkData.passableMap = &generateHeightChunkBuffer.passableMap; + generatorChunkData.start = start; + generatorChunkData.numberOfPoles = generateHeightPoles; + generatorChunkData.originOffset = originOffset; + generatorChunkData.upperPad = upperPad; + generatorChunkData.distanceBetweenPoles = distanceBetweenPoles; + generatorChunkData.shaderGroup = &terrainGenerator->getShaderGroup (); + generatorChunkData.floraGroup = &terrainGenerator->getFloraGroup (); + generatorChunkData.radialGroup = &terrainGenerator->getRadialGroup (); + generatorChunkData.environmentGroup = &terrainGenerator->getEnvironmentGroup (); + generatorChunkData.fractalGroup = &terrainGenerator->getFractalGroup (); + generatorChunkData.bitmapGroup = &terrainGenerator->getBitmapGroup (); + + terrainGenerator->generateChunk (generatorChunkData); + + return generatorChunkData.heightMap->getData(originOffset, originOffset); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::findSurface (const Vector& position, ProceduralTerrainAppearance::SurfaceData& data) const +{ + const Chunk* chunk = findFirstRenderableChunk (position); + + return chunk && chunk->findSurface (position, data); +} + +//---------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::isPassable(const Vector& position) const +{ + if (!m_hasPassableAffectors) + return true; + + Chunk const * chunk = findFirstRenderableChunk(position); + return chunk && chunk->isPassable(position); +} + +//---------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::isPassableForceChunkCreation(const Vector& position) const +{ + if (!m_hasPassableAffectors) + return true; + + Chunk const * chunk = findChunk(position, 1); + if (!chunk) + { + const_cast (this)->createChunk (position, 1); + chunk = findChunk (position, 1); + } + + bool const isPassable = (chunk && chunk->isPassable(position)); + +#ifndef WIN32 + if (!chunk) + LOG("PTA::isPFCC", ("(%g,%g,%g) chunk is NULL, %d/%d/%d/%d", position.x, position.y, position.z, getNumberOfChunks(), maximumNumberOfChunksAllowed, getNumberOfReferenceObjects(), maximumNumberOfChunksAlongSide)); +#endif + + return isPassable; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::findStaticCollidableFlora (const Vector& position, ProceduralTerrainAppearance::StaticFloraData& data, bool& floraAllowed) const +{ + const Chunk* chunk = findFirstRenderableChunk (position); + + return chunk && chunk->findStaticCollidableFlora (position, data, floraAllowed); +} //lint !e1763 // function marked as const modifies class + +//=================================================================== + +static int calculateFloraTileX (const Vector& position, const float tileWidthInMeters) +{ + const int x = static_cast ((position.x >= 0.f) ? floorf (position.x / tileWidthInMeters) : ceilf (position.x / tileWidthInMeters)); + + //-- zero is not a valid chunk index + return (position.x < 0.f) ? x - 1 : x; +} + +//------------------------------------------------------------------- + +static int calculateFloraTileZ (const Vector& position, const float tileWidthInMeters) +{ + const int z = static_cast ((position.z >= 0.f) ? floorf (position.z / tileWidthInMeters) : ceilf (position.z / tileWidthInMeters)); + + //-- zero is not a valid chunk index + return (position.z < 0.f) ? z - 1 : z; +} + +//------------------------------------------------------------------- + +static uint32 calculateFloraMapKey (const int x, const int z, const int mapWidthInTiles) +{ + DEBUG_FATAL (x < 0, ("")); + DEBUG_FATAL (z < 0, ("")); + return static_cast (z * mapWidthInTiles + x); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::_legacyGetStaticCollidableFloraData(StaticFloraData &o_data, const Chunk* const chunk, const Vector &floraPosition) +{ + bool chunkFloraAllowed=false; + bool chunkHasFlora=false; + + if (chunk->findStaticCollidableFlora (floraPosition, o_data, chunkFloraAllowed)) + { + if (o_data.familyChildData->familyId) + { + chunkHasFlora = true; + } + else + { + chunkHasFlora = false; + } + } + return chunkHasFlora; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::_legacyCreateFlora(const Chunk* const chunk) +{ + NOT_NULL (chunk); + + const float floraTileWidthInMeters = 16.f; + const float floraTileBorderInMeters = proceduralTerrainAppearanceTemplate->getCollidableTileBorder (); + const int floraMapWidthInTiles = static_cast (getMapWidthInMeters () / floraTileWidthInMeters); + const int floraTileCenterOffset = floraMapWidthInTiles / 2; + + const BoxExtent& extent = chunk->getBoxExtent (); + const Vector start = Vector::linearInterpolate (extent.getMin (), extent.getMax (), 0.5f); + const int floraTileX = calculateFloraTileX (start, floraTileWidthInMeters); + const int floraTileZ = calculateFloraTileZ (start, floraTileWidthInMeters); + const int keyX = floraTileX + floraTileCenterOffset; + const int keyZ = floraTileZ + floraTileCenterOffset; + const uint32 key = calculateFloraMapKey (keyX, keyZ, floraMapWidthInTiles); + + FloraMap::iterator iter = m_floraMap->find (key); + if (iter == m_floraMap->end ()) + { + RandomGenerator random (key); + + const float xOffset = random.randomReal (0.f, 1.f); + const float zOffset = random.randomReal (0.f, 1.f); + + const Vector floraTileStart (static_cast (floraTileX) * floraTileWidthInMeters, 0.f, static_cast (floraTileZ) * floraTileWidthInMeters); + const Vector floraPositionWithinTile (xOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters, 0.f, zOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters); + + const Rectangle2d extent2d (extent.getLeft (), extent.getBack (), extent.getRight (), extent.getFront ()); + + Vector floraPosition = floraTileStart + floraPositionWithinTile; + if ( !shouldClearCollidableFlora (floraPosition) + && extent2d.isWithin(floraPosition.x, floraPosition.z) + && chunk->getHeightAt(floraPosition, &floraPosition.y) + ) + { + StaticFloraData data; + const bool chunkHasFlora = _legacyGetStaticCollidableFloraData(data, chunk, floraPosition); + + /////////////////////////////////////////////////////////////////////////////// + + if (chunkHasFlora) + { + DEBUG_REPORT_LOG (ms_logFloraCreation, ("flora create: <%1.2f, %1.2f> %i %1.2f [%s]\n", floraPosition.x, floraPosition.z, data.familyChildData->familyId, data.childChoice, data.familyChildData->appearanceTemplateName)); + + iter = m_cachedFloraMap->find (key); + if (iter != m_cachedFloraMap->end ()) + { + iter->second->addToWorld (); + IGNORE_RETURN (m_floraMap->insert (std::make_pair (key, iter->second))); + + m_cachedFloraMap->erase (iter); + } + else + { + const float yaw = random.randomReal (0.f, PI_TIMES_2); + const float scale = data.familyChildData->shouldScale ? random.randomReal (data.familyChildData->minimumScale, data.familyChildData->maximumScale) : 1.f; + + Object* const object = new Object (); + object->yaw_o (yaw); + Appearance * const appearance = AppearanceTemplateList::createAppearance (FileName (FileName::P_appearance, data.familyChildData->appearanceTemplateName)); + appearance->setKeepAlive (true); + object->setAppearance (appearance); + object->setScale (Vector::xyz111 * scale); + + if (ms_createFloraHookFunction) + ms_createFloraHookFunction (*object); + + object->setPosition_p (floraPosition); + + CollisionProperty* const collisionProperty = new CollisionProperty (*object); + collisionProperty->setFlora (true); + object->addProperty (*collisionProperty); + + object->addToWorld (); + + IGNORE_RETURN (m_floraMap->insert (std::make_pair (key, object))); + } //lint !e429 //-- collisionProperty has not been freed or returned + } + } + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::createFlora (const Chunk* const chunk) +{ + if (proceduralTerrainAppearanceTemplate->getLegacyMode()) + { + _legacyCreateFlora(chunk); + return; + } + + NOT_NULL (chunk); + + const float floraTileWidthInMeters = 16.f; + const float floraTileBorderInMeters = proceduralTerrainAppearanceTemplate->getCollidableTileBorder (); + const int floraMapWidthInTiles = static_cast (getMapWidthInMeters () / floraTileWidthInMeters); + const int floraTileCenterOffset = floraMapWidthInTiles / 2; + + const BoxExtent& extent = chunk->getBoxExtent (); + const Vector start = Vector::linearInterpolate (extent.getMin (), extent.getMax (), 0.5f); + const int floraTileX = calculateFloraTileX (start, floraTileWidthInMeters); + const int floraTileZ = calculateFloraTileZ (start, floraTileWidthInMeters); + const int keyX = floraTileX + floraTileCenterOffset; + const int keyZ = floraTileZ + floraTileCenterOffset; + const uint32 key = calculateFloraMapKey(keyX, keyZ, floraMapWidthInTiles); + + FloraMap::iterator iter = m_floraMap->find (key); + if (iter != m_floraMap->end ()) + { + return; + } + + // ----------------------------------------------------- + // flora position + /* + const int modKeyX = keyX&7; + const int modKeyZ = keyZ&7; + const uint32 seed = calculateFloraMapKey(modKeyX, modKeyZ, floraMapWidthInTiles); + RandomGenerator random (seed); + */ + RandomGenerator random (key); + + const float xOffset = random.randomReal(0.f, 1.f); + const float zOffset = random.randomReal(0.f, 1.f); + + const Vector floraTileStart (static_cast (floraTileX) * floraTileWidthInMeters, 0.f, static_cast (floraTileZ) * floraTileWidthInMeters); + const Vector floraPositionWithinTile (xOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters, 0.f, zOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters); + + const Rectangle2d extent2d (extent.getLeft (), extent.getBack (), extent.getRight (), extent.getFront ()); + + Vector floraPosition = floraTileStart + floraPositionWithinTile; + // ----------------------------------------------------- + + // ----------------------------------------------------- + if (!extent2d.isWithin(floraPosition.x, floraPosition.z)) + { + return; + } + + if (!chunk->floraAllowed(floraPosition)) + { + return; + } + + if (shouldClearCollidableFlora(floraPosition)) + { + return; + } + // ----------------------------------------------------- + + + // ----------------------------------------------------- + //mapFgi = scmap[modKeyZ*floraMapWidthInTiles + modKeyX]; + int mapFamily = proceduralTerrainAppearanceTemplate->getStaticCollidableFloraFamily(keyX, keyZ); + if (mapFamily==0) + { + return; + } + + FloraGroup::Info mapFgi; + StaticFloraData data; + + mapFgi.setFamilyId(mapFamily); + + float seedX = floorf(floraPosition.x); + float seedZ = floorf(floraPosition.z); + uint32 hash = CoordinateHash::hashTuple(seedX, seedZ); + float childChoice = CoordinateHash::makeFloat(hash); + mapFgi.setChildChoice(childChoice); + + FloraGroup const & floraGroup = getFloraGroup(); + + //-- family data + data.floats = floraGroup.getFamilyFloats(mapFgi.getFamilyId()); + data.childChoice = mapFgi.getChildChoice (); + + //-- family child data + data.familyChildData = &floraGroup.createFlora(mapFgi); + + // ----------------------------------------------------- + + DEBUG_REPORT_LOG (ms_logFloraCreation, ("flora create: <%1.2f, %1.2f> %i %1.2f [%s]\n", floraPosition.x, floraPosition.z, data.familyChildData->familyId, data.childChoice, data.familyChildData->appearanceTemplateName)); + + iter = m_cachedFloraMap->find (key); + if (iter != m_cachedFloraMap->end ()) + { + iter->second->addToWorld (); + IGNORE_RETURN (m_floraMap->insert (std::make_pair (key, iter->second))); + + m_cachedFloraMap->erase (iter); + } + else + { + + // ----------------------------------------------------- + // we're going to need the height now. + floraPosition.y=proceduralTerrainAppearanceTemplate->getStaticCollidableFloraHeight(keyX, keyZ); + /* + if (!chunk->getHeightAt(floraPosition, &floraPosition.y)) + { + return; + } + */ + // ----------------------------------------------------- + + const float yaw = random.randomReal(0.f, PI_TIMES_2); + const float scale = data.familyChildData->shouldScale ? random.randomReal(data.familyChildData->minimumScale, data.familyChildData->maximumScale) : 1.f; + + Object* const object = new Object (); + object->yaw_o (yaw); + Appearance * const appearance = AppearanceTemplateList::createAppearance (FileName (FileName::P_appearance, data.familyChildData->appearanceTemplateName)); + appearance->setKeepAlive (true); + object->setAppearance (appearance); + object->setScale (Vector::xyz111 * scale); + + if (ms_createFloraHookFunction) + { + ms_createFloraHookFunction(*object); + } + + object->setPosition_p (floraPosition); + + CollisionProperty* const collisionProperty = new CollisionProperty (*object); + collisionProperty->setFlora (true); + object->addProperty (*collisionProperty); + + object->addToWorld (); + + IGNORE_RETURN (m_floraMap->insert (std::make_pair (key, object))); + } //lint !e429 //-- collisionProperty has not been freed or returned +} + +//------------------------------------------------------------------- + +template +inline bool WithinRangeInclusiveExclusive (const T &rangeMin, const T &value, const T &rangeMax) +{ + DEBUG_FATAL (rangeMax < rangeMin, ("range error: max value is less than min value")); + return (value >= rangeMin) && (value < rangeMax); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::destroyFlora (const Chunk* const chunk) +{ + NOT_NULL (chunk); + + const float floraTileWidthInMeters = 16.f; + const int floraMapWidthInTiles = static_cast (getMapWidthInMeters () / floraTileWidthInMeters); + const int floraTileCenterOffset = floraMapWidthInTiles / 2; + + const BoxExtent& extent = chunk->getBoxExtent (); + const Vector start = Vector::linearInterpolate (extent.getMin (), extent.getMax (), 0.5f); + const int floraTileX = calculateFloraTileX (start, floraTileWidthInMeters); + const int floraTileZ = calculateFloraTileZ (start, floraTileWidthInMeters); + const int keyX = floraTileX + floraTileCenterOffset; + const int keyZ = floraTileZ + floraTileCenterOffset; + const uint32 key = calculateFloraMapKey (keyX, keyZ, floraMapWidthInTiles); + + FloraMap::iterator iter = m_floraMap->find (key); + if (iter != m_floraMap->end ()) + { + Object* const object = iter->second; + const Vector position = object->getPosition_w (); + if (WithinRangeInclusiveExclusive (extent.getLeft (), position.x, extent.getRight ()) && + WithinRangeInclusiveExclusive (extent.getBack (), position.z, extent.getFront ())) + { +#ifdef _DEBUG + const char* const appearanceTemplateName = object->getAppearance () && object->getAppearance ()->getAppearanceTemplate () ? object->getAppearance ()->getAppearanceTemplate ()->getCrcName ().getString () : 0; + DEBUG_REPORT_LOG (ms_logFloraCreation, ("flora cache: <%1.2f, %1.2f> [%s]\n", position.x, position.z, appearanceTemplateName ? appearanceTemplateName : "null")); +#endif + iter->second->removeFromWorld (); + IGNORE_RETURN (m_cachedFloraMap->insert (std::make_pair (key, iter->second))); + + m_floraMap->erase (iter); + } + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::prepareForDelete (const Chunk* const chunk) +{ + destroyFlora (chunk); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::addClearCollidableFloraObject (const Object* const object, const Vector& position, const float radius) +{ + ClearCollidableFloraEntry entry; + entry.position.set (position.x, 0.f, position.z); + entry.radius = radius; + IGNORE_RETURN (m_clearCollidableFloraMap->insert (std::make_pair (object, entry))); + + //-- clear the flora objects that have been created + const int x0 = calculateChunkX (position.x - radius); + const int x1 = calculateChunkX (position.x + radius); + const int z0 = calculateChunkZ (position.z - radius); + const int z1 = calculateChunkZ (position.z + radius); + + int x; + int z; + for (z = z0; z <= z1; ++z) + for (x = x0; x <= x1; ++x) + { + const Chunk* const chunk = findChunk (x, z, 1); + if (chunk) + { + destroyFlora (chunk); + createFlora (chunk); + } + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::removeClearCollidableFloraObject (const Object* const object) +{ + ClearCollidableFloraMap::iterator iter = m_clearCollidableFloraMap->find (object); + if (iter != m_clearCollidableFloraMap->end ()) + { + //-- go through the existing chunks for the area and mark them as visible again + const ClearCollidableFloraEntry entry = iter->second; + + m_clearCollidableFloraMap->erase (iter); + + //-- clear the flora objects that have been created + const int x0 = calculateChunkX (entry.position.x - entry.radius); + const int x1 = calculateChunkX (entry.position.x + entry.radius); + const int z0 = calculateChunkZ (entry.position.z - entry.radius); + const int z1 = calculateChunkZ (entry.position.z + entry.radius); + + if (World::isValid ()) + { + for (int z = z0; z <= z1; ++z) + for (int x = x0; x <= x1; ++x) + { + const Chunk* const chunk = findChunk (x, z, 1); + if (chunk) + createFlora (chunk); + } + } + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearance::debugDump () const +{ +#ifdef _DEBUG + TerrainAppearance::debugDump (); + + DEBUG_REPORT_PRINT (true, ("-- ProceduralTerrainAppearance\n")); + DEBUG_REPORT_PRINT (true, (" maximumNumberOfChunks = %i\n", maximumNumberOfChunksAllowed)); + DEBUG_REPORT_PRINT (true, (" numberOfChunks = %i\n", getNumberOfChunks ())); + DEBUG_REPORT_PRINT (true, (" flora map size = %i\n", m_floraMap->size ())); + DEBUG_REPORT_PRINT (true, (" cached flora map size = %i\n", m_cachedFloraMap->size ())); + DEBUG_REPORT_PRINT (true, (" clear flora map size = %i\n", m_clearCollidableFloraMap->size ())); + DEBUG_REPORT_PRINT (true, ("chunksGeneratedThisFrame = %i\n", m_chunksGeneratedThisFrame)); + + const Chunk* const chunk = findAnyChunk (); + if (chunk) + { + const int chunkMemorySize = chunk->getChunkMemorySize (); + DEBUG_REPORT_PRINT (true, (" chunkMemorySize = %i\n", chunkMemorySize)); + DEBUG_REPORT_PRINT (true, (" terrainMemorySize = ~%i\n", chunkMemorySize * getNumberOfChunks ())); + } +#endif +} + +// ---------------------------------------------------------------------- + +ShaderGroup const & ProceduralTerrainAppearance::getShaderGroup() const +{ + return proceduralTerrainAppearanceTemplate->getTerrainGenerator()->getShaderGroup(); +} + +// ---------------------------------------------------------------------- + +FloraGroup const & ProceduralTerrainAppearance::getFloraGroup() const +{ + return proceduralTerrainAppearanceTemplate->getTerrainGenerator()->getFloraGroup(); +} + +// ---------------------------------------------------------------------- + +RadialGroup const & ProceduralTerrainAppearance::getRadialGroup() const +{ + return proceduralTerrainAppearanceTemplate->getTerrainGenerator()->getRadialGroup(); +} + +// ---------------------------------------------------------------------- + +EnvironmentGroup const & ProceduralTerrainAppearance::getEnvironmentGroup() const +{ + return proceduralTerrainAppearanceTemplate->getTerrainGenerator()->getEnvironmentGroup(); +} + +//---------------------------------------------------------------------- + +bool ProceduralTerrainAppearance::hasPassableAffectors() const +{ + return m_hasPassableAffectors; +} + +//=================================================================== +// PRIVATE ProceduralTerrainAppearance +//=================================================================== + +bool ProceduralTerrainAppearance::shouldClearCollidableFlora (const Vector& position) const +{ + const Vector position2d (position.x, 0.f, position.z); + + ClearCollidableFloraMap::iterator iter = m_clearCollidableFloraMap->begin (); + for (; iter != m_clearCollidableFloraMap->end (); ++iter) + if (iter->second.position.magnitudeBetweenSquared (position2d) < sqr (iter->second.radius)) + return true; + + return false; +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.h new file mode 100644 index 00000000..d256c916 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearance.h @@ -0,0 +1,456 @@ +//=================================================================== +// +// ProceduralTerrainAppearance.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_ProceduralTerrainAppearance_H +#define INCLUDED_ProceduralTerrainAppearance_H + +//=================================================================== + +#include "sharedCollision/BoxExtent.h" +#include "sharedMath/Sphere.h" +#include "sharedMath/Vector.h" +#include "sharedTerrain/TerrainAppearance.h" +#include "sharedTerrain/TerrainGenerator.h" + +class Appearance; +class Camera; +class Iff; +class Object; +class ObjectList; +class ObjectTemplate; +class ProceduralTerrainAppearanceTemplate; +class Rectangle2d; +class SpatialSubdivisionHandle; + +//------------------------------------------------------------------- +// +// ProceduralTerrainAppearance holds a list of generated terrain chunks +// +// data for the template is as follows: +// +// mapWidthInMeters supplied by designers/artists (i.e. 4096m x 4096m) +// +// chunkWidthInMeters supplied by designers/artists (i.e. 32m) +// +// tileWidthInMeters width of a terrain tile in meters +// tiles are composed of a fan of 8 polygons +// +// numberOfTilesPerChunk number of tiles per chunk for width and height (square) +// total number of tiles per chunk is numberOfTilesPerChunk^2 +// +// numberOfTiles along width = numberOfChunks * numberOfTilesPerChunk +// total number of tiles = numberOfTiles^2 +// +// tiles are organized in the following vertex structure. the purpose of +// indirection is to allow me to create the tile vertex arrays in a loop +// +// 2 3 4 +// x-----x-----x +// |\ | /| +// | \ | / | +// | 0\|/ | +// 1 x-----x-----x 5 +// | /|\ | +// | / | \ | +// |/ | \| +// x-----x-----x +// 8 7 6 +// + +class ProceduralTerrainAppearance : public TerrainAppearance +{ +public: + + typedef void (*CreateFloraHookFunction) (Object& object); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // CreateChunkData defines the data needed to generate a chunk in the terrain system + // + struct CreateChunkData + { + public: + + //-- scratchpad (using TerrainGenerator::createChunkBuffer) + TerrainGenerator::CreateChunkBuffer* createChunkBuffer; + + //-- coordinate of chunk (x,z) in chunk space + int chunkX; + int chunkZ; + + //-- number of shader tiles + int numberOfTilesPerChunk; + + //-- chunk width + float chunkWidthInMeters; + float tileWidthInMeters; + + Vector start; + + int originOffset; + int numberOfPoles; + + //-- + const ShaderGroup* shaderGroup; + const FloraGroup* floraGroup; + const RadialGroup* radialGroup; + const EnvironmentGroup* environmentGroup; + const FractalGroup* fractalGroup; + const BitmapGroup* bitmapGroup; + + uint8 hasLargerNeighborFlags; + + private: + + CreateChunkData (); + CreateChunkData (const CreateChunkData& rhs); + CreateChunkData& operator= (const CreateChunkData& rhs); + + public: + + explicit CreateChunkData (TerrainGenerator::CreateChunkBuffer* newCreateChunkBuffer); + virtual ~CreateChunkData (); + + virtual void validate () const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // SurfaceData returns the object template at a given tile of the terrain system + // + struct SurfaceData + { + public: + + const ObjectTemplate* objectTemplate; + + public: + + SurfaceData (); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // StaticFloraData defines information about what flora exists at a point + // + struct StaticFloraData + { + public: + + //-- family data + bool floats; + float childChoice; + + //-- family child data + FloraGroup::FamilyChildData const * familyChildData; + + public: + + StaticFloraData (); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Chunk defines a chunk of terrain in the terrain system + // + class Chunk : public Appearance + { + public: + + explicit Chunk (ProceduralTerrainAppearance& proceduralTerrainAppearance); + virtual ~Chunk (); + + const ProceduralTerrainAppearanceTemplate *getAppearanceTemplate() const { return m_proceduralTerrainAppearance.proceduralTerrainAppearanceTemplate; } + + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const = 0; + virtual bool getHeightAt (const Vector& pos, float* height) const = 0; + virtual bool getHeightAt (const Vector& pos, float* height, Vector* normal) const = 0; + + const BoxExtent& getBoxExtent() const { return m_boxExtent; } + + //-- coordinate of chunk (x,z) in chunk space + int getChunkX() const { return chunkX; } + int getChunkZ() const { return chunkZ; } + + float getChunkWidthInMeters () const { return chunkWidthInMeters; } + + bool getHasLargerNeighbor (int dir) const; + bool getHasAnyLargerNeighbors () const { return hasLargerNeighborFlags!=0; } + + bool findSurface (const Vector& position, SurfaceData& data) const; + void setPassable(int tileX, int tileZ, bool isPassable); + bool isPassable(const Vector& position) const; + + bool isExcluded(const Vector& position) const; + bool isExcluded(int tileX, int tileZ) const; + + bool floraAllowed(const Vector& position) const { return _floraAllowed(position.x, position.z); } + bool findStaticCollidableFlora (const Vector& position, StaticFloraData& data, bool& floraAllowed) const; + bool findStaticCollidableFlora (const Vector& position, FloraGroup::Info& data, bool& floraAllowed) const; + + virtual int getChunkMemorySize () const; + +#ifdef _DEBUG + virtual bool debugRenderingEnabled () const; +#endif + + SpatialSubdivisionHandle *getSpatialSubdivisionHandle() const { return m_spatialSubdivisionHandle; } + void setSpatialSubdivisionHandle(SpatialSubdivisionHandle *h) const { m_spatialSubdivisionHandle = h; } + + public: + + static void setDrawVertexNormals (bool drawVertexNormals); + static bool getDrawVertexNormals (); + static void setDrawExtent (bool drawExtent); + static bool getDrawExtent (); + + protected: + + void _findMapXz (const Vector& position, int& x, int& z) const; + void _findTileXz(Vector const & position, int & x, int & z) const; + + void _makeStaticFloraData(StaticFloraData& o_data, const FloraGroup::Info &i_groupInfo) const; + bool _floraAllowed(float positionX, float positionZ) const; + bool _findStaticFlora(const Array2d& floraMap, float positionX, float positionZ, StaticFloraData& data, bool& floraAllowed) const; + bool _findStaticFlora(const Array2d& floraMap, float positionX, float positionZ, FloraGroup::Info &data, bool& floraAllowed) const; + void _prepareForDelete(); + + void _setExcluded(int tileX, int tileZ); + + protected: + + ProceduralTerrainAppearance & m_proceduralTerrainAppearance; + + //-- coordinate of chunk (x,z) in chunk space + int chunkX; + int chunkZ; + + float chunkWidthInMeters; + uint8 hasLargerNeighborFlags; + + int originOffset; + int numberOfPoles; + + BoxExtent m_boxExtent; + + Array2d* shaderMap; + Array2d * m_floraStaticCollidableMap; + + unsigned m_excluded, m_passable; + + mutable SpatialSubdivisionHandle * m_spatialSubdivisionHandle; + + private: + + Chunk (); + Chunk (const Chunk& rhs); + Chunk& operator= (const Chunk& rhs); + + private: + + static bool ms_drawVertexNormals; + static bool ms_drawExtent; + }; + + friend class Chunk; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + + ProceduralTerrainAppearance (const ProceduralTerrainAppearanceTemplate* appearanceTemplate); + virtual ~ProceduralTerrainAppearance () = 0; + + virtual const Sphere& getSphere () const; + virtual bool getHeight (const Vector& position_o, float& height) const; + virtual bool getHeight (const Vector& position_o, float& height, Vector& normal) const; + virtual bool getHeightForceChunkCreation (const Vector& position_o, float& height) const; + virtual const ObjectTemplate* getSurfaceProperties (const Vector& position_o) const; + virtual bool getWaterHeight (const Vector& position_o, float& height) const; + virtual bool getWaterHeight (const Vector& position_o, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater=false) const; + TerrainGeneratorWaterType getWaterType (const Vector& position_o) const; + virtual bool getWater (int chunkX, int chunkZ) const; + virtual bool getSlope (int chunkX, int chunkZ) const; + virtual bool getWater (const Rectangle2d& rectangle) const; + virtual bool getSlope (const Rectangle2d& rectangle) const; + virtual float getChunkWidthInMeters () const; + virtual float getMapWidthInMeters () const; + virtual float getEnvironmentCycleTime () const; + virtual int getNumberOfChunks () const = 0; + virtual int calculateChunkX (float positionX) const; + virtual int calculateChunkZ (float positionZ) const; + virtual float getChunkHeight (int chunkX, int chunkZ) const; + virtual const BoxExtent* getChunkExtent (const Vector& position_o) const; + virtual const BoxExtent* getChunkExtentForceChunkCreation (const Vector& position_o) const; + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParamters, CollisionInfo & result) const = 0; + virtual float alter (float time) = 0; + + int getNumberOfTilesPerChunk () const; + + bool findSurface (const Vector& position, SurfaceData& data) const; + bool findStaticCollidableFlora (const Vector& position, StaticFloraData& data, bool& floraAllowed) const; + virtual bool isPassable(const Vector& position) const; + virtual bool isPassableForceChunkCreation(const Vector& position) const; + + //-- run-time rule addition interface + void addLayer (const TerrainGenerator::Layer* layer); + void removeLayer (const TerrainGenerator::Layer* layer); + void prepareGenerator (); + float generateHeight_expensive (const Vector2d& position_w); + + virtual void addClearCollidableFloraObject (const Object* object, const Vector& position_w, float radius); + virtual void removeClearCollidableFloraObject (const Object* object); + + virtual void debugDump () const; + + ShaderGroup const & getShaderGroup() const; + FloraGroup const & getFloraGroup() const; + RadialGroup const & getRadialGroup() const; + EnvironmentGroup const & getEnvironmentGroup() const; + virtual bool hasPassableAffectors() const; + +public: + + static void install (); + + static void setCreateFloraHookFunction (CreateFloraHookFunction createFloraHookFunction); + static void setMaximumNumberOfChunksAllowed (int newMaximumNumberOfChunksAllowed); + +protected: + + class ClearCollidableFloraEntry + { + public: + + Vector position; + float radius; + }; + +protected: + + typedef stdmap::fwd ClearCollidableFloraMap; + +protected: + + virtual const Chunk* findChunk (int x, int z, int chunkSize) const = 0; + virtual const Chunk* findFirstRenderableChunk (int x, int z) const = 0; + virtual const Chunk* findAnyChunk () const; + virtual void addChunk (Chunk* chunk, int chunkSize) = 0; + virtual void createChunk (int x, int z, int chunkSize, unsigned hasLargerNeighborFlags) = 0; + virtual void removeUnnecessaryChunk () = 0; + + bool areValidChunkIndices (int x, int z) const; + const Chunk* findChunk (const Vector& position, int chunkSize) const; + const Chunk* findFirstRenderableChunk (const Vector& position) const; + const Chunk* findFirstRenderableChunk2D(float positionX, float positionZ) const; + + void createChunk (const Vector& position, int chunkSize); + virtual void prepareForDelete (const Chunk* chunk); + + bool _legacyGetStaticCollidableFloraData(StaticFloraData &o_data, const Chunk* const chunk, const Vector &floraPosition); + void _legacyCreateFlora (const Chunk* chunk); + void createFlora (const Chunk* chunk); + void destroyFlora (const Chunk* chunk); + + void verifyChunk (const Chunk* chunk) const; + + void setClient (); + + const ClearCollidableFloraMap* getClearCollidableFloraMap () const; + +protected: + + //-- + const int originOffset; + const int upperPad; + const int numberOfPoles; + + //-- culling sphere + mutable Sphere sphere; + + //-- scratchpad for creating chunks + TerrainGenerator::CreateChunkBuffer createChunkBuffer; + + //-- scratchpad for [expensively] creating just height data + TerrainGenerator::CreateChunkBuffer generateHeightChunkBuffer; + + //-- maximum number of chunks to hold + int maximumNumberOfChunksAllowed; + int maximumNumberOfChunksAlongSide; + + const ProceduralTerrainAppearanceTemplate* proceduralTerrainAppearanceTemplate; + + typedef stdvector::fwd RunTimeRuleList; + RunTimeRuleList* m_runTimeRuleList; + + int m_chunksGeneratedThisFrame; + +protected: + + static CreateFloraHookFunction ms_createFloraHookFunction; + +private: + + static void remove (); + +private: + + bool shouldClearCollidableFlora (const Vector& position) const; + +private: + + ProceduralTerrainAppearance (); + ProceduralTerrainAppearance (const ProceduralTerrainAppearance&); + ProceduralTerrainAppearance& operator= (const ProceduralTerrainAppearance&); + +private: + + bool m_server; + + typedef stdmap::fwd FloraMap; + FloraMap* const m_floraMap; + FloraMap* const m_cachedFloraMap; + + ClearCollidableFloraMap* const m_clearCollidableFloraMap; + + bool m_hasPassableAffectors; +}; + +//------------------------------------------------------------------- + +inline +bool ProceduralTerrainAppearance::Chunk::getHasLargerNeighbor (int direction) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, direction, 4); + + return 0!=(hasLargerNeighborFlags & (1< +#include + +//=================================================================== + +namespace +{ + struct StaticFloraSampleFileHeader + { + char terrainName[64]; + float floraTileWidthInMeters; + int numberOfFloraSampled; + }; +} + +//=================================================================== + +ProceduralTerrainAppearanceTemplate::ProceduralTerrainAppearanceTemplate( + const char* filename, + Iff* iff, + bool legacyMode, + int chunkOriginOffset, // size of sample pad on lower side of chunk. + int chunkUpperPad, // size of sample pad on upper side of chunk. + bool samplingMode +) : + AppearanceTemplate (filename), + m_name (0), + m_mapWidthInMeters (0), + m_chunkWidthInMeters (0), + m_numberOfTilesPerChunk (0), + m_useGlobalWaterTable (false), + m_globalWaterTableHeight (0), + m_globalWaterTableShaderTemplateName (0), + m_globalWaterTableShaderSize (2.f), + m_environmentCycleTime (1800.f), + m_collidableMinimumDistance (0.f), + m_collidableMaximumDistance (0.f), + m_collidableTileSize (0.f), + m_collidableTileBorder (0.f), + m_collidableSeed (0), + m_nonCollidableMinimumDistance (0.f), + m_nonCollidableMaximumDistance (0.f), + m_nonCollidableTileSize (0.f), + m_nonCollidableTileBorder (0.f), + m_nonCollidableSeed (0), + m_radialMinimumDistance (0.f), + m_radialMaximumDistance (0.f), + m_radialTileSize (0.f), + m_radialTileBorder (0.f), + m_radialSeed (0), + m_farRadialMinimumDistance (0.f), + m_farRadialMaximumDistance (0.f), + m_farRadialTileSize (0.f), + m_farRadialTileBorder (0.f), + m_farRadialSeed (0), + m_legacyMap(false), + m_legacyMode(legacyMode), + m_samplingMode(samplingMode), + m_tileWidthInMeters (0), + m_chunkOriginOffset(legacyMode ? 3 : chunkOriginOffset), + m_chunkUpperPad(legacyMode ? 3 : chunkUpperPad), + m_terrainGenerator (0), + m_bakedTerrain (0), + m_waterTableList (new WaterTableList), + m_ribbonQuadList (new RibbonQuadList), + m_ribbonEndCapList (new RibbonEndCapList), + m_floraTileWidthInMeters(16.0f), + m_mapWidthInFlora(0), + m_staticCollidableFloraMap(0), + m_staticCollidableFloraHeightMap(0) +{ + + NOT_NULL (iff); + load (*iff); + + //-- + + createWaterTableAndRibbonQuadLists (); +} + +//------------------------------------------------------------------- + +ProceduralTerrainAppearanceTemplate::~ProceduralTerrainAppearanceTemplate () +{ + //-- delete name + delete [] m_name; + m_name = 0; + + delete [] m_globalWaterTableShaderTemplateName; + m_globalWaterTableShaderTemplateName = 0; + + delete m_terrainGenerator; + m_terrainGenerator = 0; + + delete m_bakedTerrain; + m_bakedTerrain = 0; + + delete m_waterTableList; + m_waterTableList = 0; + + delete m_ribbonQuadList; + m_ribbonQuadList = 0; + + delete m_ribbonEndCapList; + m_ribbonEndCapList = 0; + + _destroyStaticCollidableFloraMaps(); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::_setSamplingParameters(bool legacyMode, int chunkOriginOffset, int chunkUpperPad) +{ + m_legacyMode = legacyMode; + m_chunkOriginOffset = legacyMode ? 3 : chunkOriginOffset; + m_chunkUpperPad = legacyMode ? 3 : chunkUpperPad; +} + +//------------------------------------------------------------------- + +const char* ProceduralTerrainAppearanceTemplate::getName () const +{ + return m_name; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getMapWidthInMeters () const +{ + return m_mapWidthInMeters; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getChunkWidthInMeters () const +{ + return m_chunkWidthInMeters; +} + +//------------------------------------------------------------------- + +int ProceduralTerrainAppearanceTemplate::getNumberOfTilesPerChunk () const +{ + return m_numberOfTilesPerChunk; +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearanceTemplate::getUseGlobalWaterTable () const +{ + return m_useGlobalWaterTable; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getGlobalWaterTableHeight () const +{ + return m_globalWaterTableHeight; +} + +//------------------------------------------------------------------- + +const char* ProceduralTerrainAppearanceTemplate::getGlobalWaterTableShaderTemplateName () const +{ + return m_globalWaterTableShaderTemplateName; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getGlobalWaterTableShaderSize () const +{ + return m_globalWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getCollidableMinimumDistance () const +{ + return m_collidableMinimumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getCollidableMaximumDistance () const +{ + return m_collidableMaximumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getCollidableTileSize () const +{ + return m_collidableTileSize; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getCollidableTileBorder () const +{ + return m_collidableTileBorder; +} + +//------------------------------------------------------------------- + +uint32 ProceduralTerrainAppearanceTemplate::getCollidableSeed () const +{ + return m_collidableSeed; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getNonCollidableMinimumDistance () const +{ + return m_nonCollidableMinimumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getNonCollidableMaximumDistance () const +{ + return m_nonCollidableMaximumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getNonCollidableTileSize () const +{ + return m_nonCollidableTileSize; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getNonCollidableTileBorder () const +{ + return m_nonCollidableTileBorder; +} + +//------------------------------------------------------------------- + +uint32 ProceduralTerrainAppearanceTemplate::getNonCollidableSeed () const +{ + return m_nonCollidableSeed; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getRadialMinimumDistance () const +{ + return m_radialMinimumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getRadialMaximumDistance () const +{ + return m_radialMaximumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getRadialTileSize () const +{ + return m_radialTileSize; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getRadialTileBorder () const +{ + return m_radialTileBorder; +} + +//------------------------------------------------------------------- + +uint32 ProceduralTerrainAppearanceTemplate::getRadialSeed () const +{ + return m_radialSeed; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getFarRadialMinimumDistance () const +{ + return m_farRadialMinimumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getFarRadialMaximumDistance () const +{ + return m_farRadialMaximumDistance; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getFarRadialTileSize () const +{ + return m_farRadialTileSize; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getFarRadialTileBorder () const +{ + return m_farRadialTileBorder; +} + +//------------------------------------------------------------------- + +uint32 ProceduralTerrainAppearanceTemplate::getFarRadialSeed () const +{ + return m_farRadialSeed; +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getTileWidthInMeters () const +{ + return m_tileWidthInMeters; +} + +//----------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getEnvironmentCycleTime () const +{ + return m_environmentCycleTime; +} + +//----------------------------------------------------------------- + +const TerrainGenerator* ProceduralTerrainAppearanceTemplate::getTerrainGenerator () const +{ + return m_terrainGenerator; +} + +//----------------------------------------------------------------- + +const BakedTerrain* ProceduralTerrainAppearanceTemplate::getBakedTerrain () const +{ + return m_bakedTerrain; +} + +//----------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::createWaterTableAndRibbonQuadLists (const TerrainGenerator::Layer* const layer) +{ + { + //-- check boundaries + int i; + for (i = 0; i < layer->getNumberOfBoundaries (); i++) + { + if (layer->getBoundary (i)->isActive () && layer->getBoundary (i)->getType () == TGBT_polygon) + { + const BoundaryPolygon* const boundaryPolygon = safe_cast (layer->getBoundary (i)); + + if (boundaryPolygon->isLocalWaterTable ()) + { + WaterTable waterTable; + waterTable.waterType = boundaryPolygon->getWaterType(); + waterTable.boundary = boundaryPolygon; + waterTable.height = boundaryPolygon->getLocalWaterTableHeight (); + m_waterTableList->push_back (waterTable); + } + } + + if (layer->getBoundary (i)->isActive () && layer->getBoundary (i)->getType () == TGBT_rectangle) + { + const BoundaryRectangle* const boundaryRectangle = safe_cast (layer->getBoundary (i)); + + if (boundaryRectangle->isLocalWaterTable ()) + { + WaterTable waterTable; + waterTable.waterType = boundaryRectangle->getWaterType(); + waterTable.boundary = boundaryRectangle; + waterTable.height = boundaryRectangle->getLocalWaterTableHeight (); + m_waterTableList->push_back (waterTable); + } + } + } + + //-- check for ribbon affectors + for (i = 0; i < layer->getNumberOfAffectors (); i++) + { + if (layer->getAffector (i)->isActive () && layer->getAffector (i)->getType () == TGAT_ribbon) + { + const AffectorRibbon* const affectorRibbon = safe_cast (layer->getAffector (i)); + // build the individual quads for the ribbon + + ArrayList ribbonQuadList; + affectorRibbon->createQuadList (ribbonQuadList); + if(ribbonQuadList.getNumberOfElements () != 0) + { + int j; + for(j = 0; j < ribbonQuadList.getNumberOfElements (); ++j) + { + RibbonQuad ribbonQuad; + ribbonQuad.waterType = affectorRibbon->getWaterType(); + ribbonQuad.points[0] = ribbonQuadList[j].points[0]; + ribbonQuad.points[1] = ribbonQuadList[j].points[1]; + ribbonQuad.points[2] = ribbonQuadList[j].points[2]; + ribbonQuad.points[3] = ribbonQuadList[j].points[3]; + m_ribbonQuadList->push_back(ribbonQuad); + } + } + + // endcap + const ArrayList& endCapPointList = affectorRibbon->getEndCapPointList(); + if(endCapPointList.getNumberOfElements() != 0) + { + DEBUG_FATAL((endCapPointList.getNumberOfElements() != 8),("ProceduralTerrainAppearanceTemplate::createWaterTableAndRibbonQuadLists - endcap has %d points, needs 8",endCapPointList.getNumberOfElements())); + + RibbonEndCap endCap; + endCap.waterType = affectorRibbon->getWaterType(); + endCap.height = affectorRibbon->getHeightList()[0]; + endCap.extent = affectorRibbon->getEndCapExtent(); + int j; + for(j = 0; j < endCapPointList.getNumberOfElements(); ++j) + { + endCap.points[j].x = endCapPointList[j].x; + endCap.points[j].y = endCapPointList[j].y; + } + + m_ribbonEndCapList->push_back(endCap); + } + } + } + } + + { + //-- check sublayers + int i; + for (i = 0; i < layer->getNumberOfLayers (); i++) + { + if (layer->getLayer (i)->isActive ()) + { + createWaterTableAndRibbonQuadLists (layer->getLayer (i)); + } + } + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::createWaterTableAndRibbonQuadLists () +{ + NOT_NULL (m_terrainGenerator); + NOT_NULL (m_waterTableList); + NOT_NULL (m_ribbonQuadList); + NOT_NULL (m_ribbonEndCapList); + + m_waterTableList->clear (); + m_ribbonQuadList->clear(); + m_ribbonEndCapList->clear(); + + int i; + for (i = 0; i < m_terrainGenerator->getNumberOfLayers (); i++) + { + if (m_terrainGenerator->getLayer (i)->isActive ()) + { + createWaterTableAndRibbonQuadLists (m_terrainGenerator->getLayer (i)); + } + } +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearanceTemplate::getWaterHeight (const Vector& position, float& height) const +{ + TerrainGeneratorWaterType waterType; + return getWaterHeight(position,height,waterType); +} + +//------------------------------------------------------------------- + +bool ProceduralTerrainAppearanceTemplate::getWaterHeight (const Vector& position, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater) const +{ + bool valid = false; + float result = -FLT_MAX; + waterType = TGWT_invalid; + + if (m_useGlobalWaterTable) + { + result = m_globalWaterTableHeight; + valid = true; + } + + uint i; + for (i = 0; i < m_waterTableList->size (); ++i) + { + const WaterTable& waterTable = (*m_waterTableList) [i]; + + // check if only interested in transparent water + if(ignoreNonTransparentWater && !WaterTypeManager::getTransparent(waterTable.waterType)) + continue; + + if (waterTable.boundary->isWithin (position.x, position.z)) + { + if(waterTable.height > result) + { + result = waterTable.height; + waterType = waterTable.waterType; + } + valid = true; + } + } + + Vector pos = position; + pos.y = 0.0f; + + for (i = 0; i < m_ribbonQuadList->size (); ++i) + { + const RibbonQuad& ribbonQuad = (*m_ribbonQuadList) [i]; + + // check if only interested in transparent water + if(ignoreNonTransparentWater && !WaterTypeManager::getTransparent(ribbonQuad.waterType)) + continue; + + const float highHeight = std::max(ribbonQuad.points[0].y,ribbonQuad.points[2].y); + if(highHeight < result) + continue; + + float x0 = std::min(std::min(std::min(ribbonQuad.points[0].x,ribbonQuad.points[1].x),ribbonQuad.points[2].x),ribbonQuad.points[3].x); + float z0 = std::min(std::min(std::min(ribbonQuad.points[0].z,ribbonQuad.points[1].z),ribbonQuad.points[2].z),ribbonQuad.points[3].z); + float x1 = std::max(std::max(std::max(ribbonQuad.points[0].x,ribbonQuad.points[1].x),ribbonQuad.points[2].x),ribbonQuad.points[3].x); + float z1 = std::max(std::max(std::max(ribbonQuad.points[0].z,ribbonQuad.points[1].z),ribbonQuad.points[2].z),ribbonQuad.points[3].z); + + if(pos.x < x0 || pos.x > x1 || pos.z < z0 || pos.z > z1) + continue; + + // check the 2 triangles on the quad + const Vector p0 = Vector(ribbonQuad.points[0].x,0.0f,ribbonQuad.points[0].z); + const Vector p1 = Vector(ribbonQuad.points[1].x,0.0f,ribbonQuad.points[1].z); + const Vector p2 = Vector(ribbonQuad.points[2].x,0.0f,ribbonQuad.points[2].z); + const Vector p3 = Vector(ribbonQuad.points[3].x,0.0f,ribbonQuad.points[3].z); + + const bool inPoly1 = pos.inPolygon(p0,p1,p2); + const bool inPoly2 = !inPoly1 && pos.inPolygon(p0,p2,p3); + + if(inPoly1 || inPoly2) + { + const Vector& v0 = ribbonQuad.points[0]; + Vector v1; + const Vector& v2 = ribbonQuad.points[2]; + + if(inPoly1) + { + v1 = ribbonQuad.points[1]; + } + else + { + v1 = ribbonQuad.points[3]; + } + + const Plane plane(v0,v1,v2); + const float lowHeight = std::min(ribbonQuad.points[0].y,ribbonQuad.points[2].y); + const Vector start = Vector(pos.x,highHeight + 1.0f,pos.z); + const Vector end = Vector(pos.x,lowHeight - 1.0f,pos.z); + + Vector intersection; + if(plane.findIntersection(start,end,intersection)) + { + if(intersection.y > result) + { + result = intersection.y; + waterType = ribbonQuad.waterType; + } + valid = true; + } + } + } + + for(i = 0; i < m_ribbonEndCapList->size (); ++i) + { + const RibbonEndCap& ribbonEndCap = (*m_ribbonEndCapList)[i]; + + // check if only interested in transparent water + if(ignoreNonTransparentWater && !WaterTypeManager::getTransparent(ribbonEndCap.waterType)) + continue; + + if(ribbonEndCap.extent.isWithin(pos.x,pos.z)) + { + const Vector p0 = Vector(ribbonEndCap.points[0].x,0.0f,ribbonEndCap.points[0].y); + const Vector p1 = Vector(ribbonEndCap.points[1].x,0.0f,ribbonEndCap.points[1].y); + const Vector p2 = Vector(ribbonEndCap.points[2].x,0.0f,ribbonEndCap.points[2].y); + const Vector p3 = Vector(ribbonEndCap.points[3].x,0.0f,ribbonEndCap.points[3].y); + const Vector p4 = Vector(ribbonEndCap.points[4].x,0.0f,ribbonEndCap.points[4].y); + const Vector p5 = Vector(ribbonEndCap.points[5].x,0.0f,ribbonEndCap.points[5].y); + const Vector p6 = Vector(ribbonEndCap.points[6].x,0.0f,ribbonEndCap.points[6].y); + const Vector p7 = Vector(ribbonEndCap.points[7].x,0.0f,ribbonEndCap.points[7].y); + + // check the triangles in 2 fans + if( + pos.inPolygon(p0,p1,p2) + || pos.inPolygon(p0,p2,p3) + || pos.inPolygon(p0,p3,p4) + || pos.inPolygon(p4,p5,p6) + || pos.inPolygon(p4,p6,p7) + || pos.inPolygon(p4,p7,p0) + ) + { + if(ribbonEndCap.height > result) + { + result = ribbonEndCap.height; + waterType = ribbonEndCap.waterType; + } + valid = true; + } + } + } + + if (valid) + height = result; + + return valid; +} + +//------------------------------------------------------------------- + +TerrainGeneratorWaterType ProceduralTerrainAppearanceTemplate::getWaterType (const Vector& position) const +{ + TerrainGeneratorWaterType waterType = TGWT_invalid; + float highestTableFound = -FLT_MAX; + + + // for the tables, it will return find the type of highest table + uint i; + for (i = 0; i < m_waterTableList->size (); ++i) + { + const WaterTable& waterTable = (*m_waterTableList) [i]; + + if (waterTable.boundary->isWithin (position.x, position.z) && waterTable.height > highestTableFound) + { + waterType = waterTable.waterType; + highestTableFound = waterTable.height; + } + } + + Vector pos = position; + pos.y = 0.0f; + + // for the ribbons it will return the the first ribbon type found - they shouldn't overlap and should always be above water tables + for (i = 0; i < m_ribbonQuadList->size (); ++i) + { + const RibbonQuad& ribbonQuad = (*m_ribbonQuadList) [i]; + // check the 2 triangles on the quad + const Vector p0 = Vector(ribbonQuad.points[0].x,0.0f,ribbonQuad.points[0].z); + const Vector p1 = Vector(ribbonQuad.points[1].x,0.0f,ribbonQuad.points[1].z); + const Vector p2 = Vector(ribbonQuad.points[2].x,0.0f,ribbonQuad.points[2].z); + const Vector p3 = Vector(ribbonQuad.points[3].x,0.0f,ribbonQuad.points[3].z); + + if(pos.inPolygon(p0,p1,p2) || pos.inPolygon(p0,p2,p3) + ) + { + waterType = ribbonQuad.waterType; + break; + } + } + + for(i = 0; i < m_ribbonEndCapList->size (); ++i) + { + const RibbonEndCap& ribbonEndCap = (*m_ribbonEndCapList)[i]; + if(ribbonEndCap.extent.isWithin(pos.x,pos.z)) + { + const Vector p0 = Vector(ribbonEndCap.points[0].x,0.0f,ribbonEndCap.points[0].y); + const Vector p1 = Vector(ribbonEndCap.points[1].x,0.0f,ribbonEndCap.points[1].y); + const Vector p2 = Vector(ribbonEndCap.points[2].x,0.0f,ribbonEndCap.points[2].y); + const Vector p3 = Vector(ribbonEndCap.points[3].x,0.0f,ribbonEndCap.points[3].y); + const Vector p4 = Vector(ribbonEndCap.points[4].x,0.0f,ribbonEndCap.points[4].y); + const Vector p5 = Vector(ribbonEndCap.points[5].x,0.0f,ribbonEndCap.points[5].y); + const Vector p6 = Vector(ribbonEndCap.points[6].x,0.0f,ribbonEndCap.points[6].y); + const Vector p7 = Vector(ribbonEndCap.points[7].x,0.0f,ribbonEndCap.points[7].y); + + // check the triangles in 2 fans + if( + pos.inPolygon(p0,p1,p2) + || pos.inPolygon(p0,p2,p3) + || pos.inPolygon(p0,p3,p4) + || pos.inPolygon(p4,p5,p6) + || pos.inPolygon(p4,p6,p7) + || pos.inPolygon(p4,p7,p0) + ) + { + waterType = ribbonEndCap.waterType; + break; + } + } + } + + return waterType; +} + +//------------------------------------------------------------------- + + +int ProceduralTerrainAppearanceTemplate::getStaticCollidableFloraFamily(int floraTileX, int floraTileY) const +{ + return (m_staticCollidableFloraMap) ? m_staticCollidableFloraMap->getValue(floraTileX, floraTileY) : int(0); +} + +//------------------------------------------------------------------- + +float ProceduralTerrainAppearanceTemplate::getStaticCollidableFloraHeight(int floraTileX, int floraTileY) const +{ + return (m_staticCollidableFloraHeightMap) ? m_staticCollidableFloraHeightMap->getValue(floraTileX, floraTileY) : float(0); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::_setStaticCollidableFloraInfo(FloraGroup::Info *infoMap, float *heightMap) +{ + const int mapWidthInFlora = getMapWidthInFlora(); + const int numElements = sqr(mapWidthInFlora); + + if (infoMap) + { + if (m_staticCollidableFloraMap) + { + delete m_staticCollidableFloraMap; + m_staticCollidableFloraMap=0; + } + + int *familiyIds = new int[numElements]; + for (int i=0;igetValue(x, z); + DEBUG_FATAL(v!=temp[z*mapWidthInFlora + x], ("")); + } + } + */ + + delete [] familiyIds; + + } + + if (heightMap) + { + if (m_staticCollidableFloraHeightMap) + { + delete m_staticCollidableFloraHeightMap; + m_staticCollidableFloraHeightMap=0; + } + + const float fixedPointResolution = 1.0f / 32.0f; + m_staticCollidableFloraHeightMap = new PackedFixedPointMap(mapWidthInFlora, mapWidthInFlora, fixedPointResolution, heightMap); + + /* + for (int z=0;zgetValue(x, z); + float ov = m_staticCollidableFloraHeightSamples[z*mapWidthInFlora + x]; + + float diff = fabsf(pv - ov); + DEBUG_FATAL(diff>.0101, ("")); + + } + } + */ + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::_destroyStaticCollidableFloraMaps() +{ + if (m_staticCollidableFloraMap) + { + delete m_staticCollidableFloraMap; + m_staticCollidableFloraMap=0; + } + if (m_staticCollidableFloraHeightMap) + { + delete m_staticCollidableFloraHeightMap; + m_staticCollidableFloraHeightMap=0; + } +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::_createDefaultStaticCollidableFloraMaps() +{ + _destroyStaticCollidableFloraMaps(); + const int floraWidth=getMapWidthInFlora(); + m_staticCollidableFloraMap = new PackedIntegerMap(floraWidth, floraWidth, 0); + m_staticCollidableFloraHeightMap = new PackedFixedPointMap(floraWidth, floraWidth, 1, 0); +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::load (Iff& iff) +{ + if (iff.getCurrentName () != TAG (M,P,T,A) && iff.getCurrentName () != TAG (P,T,A,T)) + return; + + iff.enterForm (); + + //DEBUG_WARNING (iff.getCurrentName () < TAG_0015, ("ProceduralTerrainAppearanceTemplate [%s]: loading older version. Please load and save this file in the TerrainEditor.", getCrcName ().getString ())); + + const Tag version = iff.getCurrentName(); + if (version>=TAG_0013 && version<=TAG_0015) + { + _load(iff, version); + } + else + { + char tagBuffer [5]; + ConvertTagToString(version, tagBuffer); + + char buffer [128]; + iff.formatLocation(buffer, sizeof (buffer)); + + FATAL(true, ("ProceduralTerrainAppearanceTemplate::load - unsupported version tag %s/%s", buffer, tagBuffer)); + } + + iff.exitForm (false); + + // ------------------------------------ + m_mapWidthInFlora = (m_floraTileWidthInMeters) ? + int(m_mapWidthInMeters / m_floraTileWidthInMeters) + : int(0); + + if ( !m_staticCollidableFloraMap + || m_staticCollidableFloraMap->getWidth()=TAG_0015) + { + m_legacyMap = iff.read_bool8(); + } + + iff.exitChunk (TAG_DATA, true); + + m_tileWidthInMeters = m_chunkWidthInMeters / m_numberOfTilesPerChunk; + + //-- get the generator from the loader + NOT_NULL (!m_terrainGenerator); + m_terrainGenerator = new TerrainGenerator (); + m_terrainGenerator->load (iff); + + NOT_NULL (!m_bakedTerrain); + m_bakedTerrain = new BakedTerrain (); + m_bakedTerrain->load (iff); + + if (version>=TAG_0015) + { + m_staticCollidableFloraMap = new PackedIntegerMap(iff); + m_staticCollidableFloraHeightMap = new PackedFixedPointMap(iff); + } + + iff.exitForm (version); +} + +//=================================================================== + +ProceduralTerrainAppearanceTemplate::WriterData::WriterData () : + name (0), + mapWidthInMeters (1024), + chunkWidthInMeters (32), + numberOfTilesPerChunk (8), + useGlobalWaterTable (false), + globalWaterTableHeight (0), + globalWaterTableShaderSize (2.f), + globalWaterTableShaderTemplateName (0), + environmentCycleTime (60.f), + collidableMinimumDistance (0.f), + collidableMaximumDistance (0.f), + collidableTileSize (0.f), + collidableTileBorder (0.f), + collidableSeed (0), + nonCollidableMinimumDistance (0.f), + nonCollidableMaximumDistance (0.f), + nonCollidableTileSize (0.f), + nonCollidableTileBorder (0.f), + nonCollidableSeed (0), + radialMinimumDistance (0.f), + radialMaximumDistance (0.f), + radialTileSize (0.f), + radialTileBorder (0.f), + radialSeed (0), + farRadialMinimumDistance (0.f), + farRadialMaximumDistance (0.f), + farRadialTileSize (0.f), + farRadialTileBorder (0.f), + farRadialSeed (0), + terrainGenerator(0), + bakedTerrain(0), + staticCollidableFloraMap(0), + staticCollidableFloraHeightMap(0) +{ +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::prepareWriterData(ProceduralTerrainAppearanceTemplate::WriterData &data) +{ + data.name = m_name; + data.mapWidthInMeters = m_mapWidthInMeters; + data.chunkWidthInMeters = m_chunkWidthInMeters; + data.numberOfTilesPerChunk = m_numberOfTilesPerChunk; + data.useGlobalWaterTable = m_useGlobalWaterTable; + data.globalWaterTableHeight = m_globalWaterTableHeight; + data.globalWaterTableShaderSize = m_globalWaterTableShaderSize; + data.globalWaterTableShaderTemplateName = m_globalWaterTableShaderTemplateName; + data.environmentCycleTime = m_environmentCycleTime; + data.collidableMinimumDistance = m_collidableMinimumDistance; + data.collidableMaximumDistance = m_nonCollidableMaximumDistance; + data.collidableTileSize = m_collidableTileSize; + data.collidableTileBorder = m_collidableTileBorder; + data.collidableSeed = m_collidableSeed; + data.nonCollidableMinimumDistance = m_nonCollidableMinimumDistance; + data.nonCollidableMaximumDistance = m_nonCollidableMaximumDistance; + data.nonCollidableTileSize = m_nonCollidableTileSize; + data.nonCollidableTileBorder = m_nonCollidableTileBorder; + data.nonCollidableSeed = m_nonCollidableSeed; + data.radialMinimumDistance = m_radialMinimumDistance; + data.radialMaximumDistance = m_radialMaximumDistance; + data.radialTileSize = m_radialTileSize; + data.radialTileBorder = m_radialTileBorder; + data.radialSeed = m_radialSeed; + data.farRadialMinimumDistance = m_farRadialMinimumDistance; + data.farRadialMaximumDistance = m_farRadialMaximumDistance; + data.farRadialTileSize = m_farRadialTileSize; + data.farRadialTileBorder = m_farRadialTileBorder; + data.farRadialSeed = m_farRadialSeed; + data.legacyMap = m_legacyMap; + data.terrainGenerator = getTerrainGenerator(); + data.bakedTerrain = getBakedTerrain(); + data.staticCollidableFloraMap = m_staticCollidableFloraMap; + data.staticCollidableFloraHeightMap = m_staticCollidableFloraHeightMap; +} + +//------------------------------------------------------------------- + +void ProceduralTerrainAppearanceTemplate::write(Iff& iff, const ProceduralTerrainAppearanceTemplate::WriterData& data) +{ + iff.insertForm(TAG (P,T,A,T)); + + iff.insertForm(TAG_0015); + + iff.insertChunk(TAG_DATA); + + iff.insertChunkString (data.name ? data.name : ""); + iff.insertChunkData (data.mapWidthInMeters); + iff.insertChunkData (data.chunkWidthInMeters); + iff.insertChunkData (data.numberOfTilesPerChunk); + iff.insertChunkData (data.useGlobalWaterTable ? static_cast (1) : static_cast (0)); + iff.insertChunkData (data.globalWaterTableHeight); + iff.insertChunkData (data.globalWaterTableShaderSize); + iff.insertChunkString (data.globalWaterTableShaderTemplateName ? data.globalWaterTableShaderTemplateName : ""); + iff.insertChunkData (data.environmentCycleTime); + iff.insertChunkData (data.collidableMinimumDistance); + iff.insertChunkData (data.collidableMaximumDistance); + iff.insertChunkData (data.collidableTileSize); + iff.insertChunkData (data.collidableTileBorder); + iff.insertChunkData (data.collidableSeed); + iff.insertChunkData (data.nonCollidableMinimumDistance); + iff.insertChunkData (data.nonCollidableMaximumDistance); + iff.insertChunkData (data.nonCollidableTileSize); + iff.insertChunkData (data.nonCollidableTileBorder); + iff.insertChunkData (data.nonCollidableSeed); + iff.insertChunkData (data.radialMinimumDistance); + iff.insertChunkData (data.radialMaximumDistance); + iff.insertChunkData (data.radialTileSize); + iff.insertChunkData (data.radialTileBorder); + iff.insertChunkData (data.radialSeed); + iff.insertChunkData (data.farRadialMinimumDistance); + iff.insertChunkData (data.farRadialMaximumDistance); + iff.insertChunkData (data.farRadialTileSize); + iff.insertChunkData (data.farRadialTileBorder); + iff.insertChunkData (data.farRadialSeed); + iff.insertChunkData (uint8(data.legacyMap ? 1 : 0)); + + iff.exitChunk(TAG_DATA); + + // ------------------------------- + NOT_NULL(data.terrainGenerator); + data.terrainGenerator->save(iff); + // ------------------------------- + + // ------------------------------- + NOT_NULL(data.bakedTerrain); + data.bakedTerrain->save(iff); + // ------------------------------- + + // ------------------------------- + if (data.staticCollidableFloraMap) + { + data.staticCollidableFloraMap->save(iff); + } + else + { + PackedIntegerMap fm(0, 0, 0); + fm.save(iff); + } + // ------------------------------- + + // ------------------------------- + if (data.staticCollidableFloraHeightMap) + { + data.staticCollidableFloraHeightMap->save(iff); + } + else + { + PackedFixedPointMap hm(0, 0, 0, 0); + hm.save(iff); + } + // ------------------------------- + + iff.exitForm(TAG_0015); + + iff.exitForm(TAG(P,T,A,T), false); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearanceTemplate.h new file mode 100644 index 00000000..5890c443 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ProceduralTerrainAppearanceTemplate.h @@ -0,0 +1,249 @@ +//=================================================================== +// +// ProceduralTerrainAppearanceTemplate.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_ProceduralTerrainAppearanceTemplate_H +#define INCLUDED_ProceduralTerrainAppearanceTemplate_H + +//=================================================================== + +#include "sharedMath/Vector2d.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedTerrain/TerrainGenerator.h" +#include "sharedTerrain/Boundary.h" + +class BakedTerrain; +class Iff; +class PackedIntegerMap; +class PackedFixedPointMap; + +//=================================================================== + +class ProceduralTerrainAppearanceTemplate : public AppearanceTemplate +{ +public: + + explicit ProceduralTerrainAppearanceTemplate( + const char* filename, + Iff* iff, + bool legacyMode, + int chunkOriginOffset, // size of sample pad on lower side of chunk. + int chunkUpperPad, // size of sample pad on upper side of chunk. + bool samplingMode=false + ); + + virtual ~ProceduralTerrainAppearanceTemplate ()=0; + + const char* getName () const; + float getMapWidthInMeters () const; + float getChunkWidthInMeters () const; + int getNumberOfTilesPerChunk () const; + bool getUseGlobalWaterTable () const; + float getGlobalWaterTableHeight () const; + const char* getGlobalWaterTableShaderTemplateName () const; + float getGlobalWaterTableShaderSize () const; + float getEnvironmentCycleTime () const; + float getCollidableMinimumDistance () const; + float getCollidableMaximumDistance () const; + float getCollidableTileSize () const; + float getCollidableTileBorder () const; + uint32 getCollidableSeed () const; + float getNonCollidableMinimumDistance () const; + float getNonCollidableMaximumDistance () const; + float getNonCollidableTileSize () const; + float getNonCollidableTileBorder () const; + uint32 getNonCollidableSeed () const; + float getRadialMinimumDistance () const; + float getRadialMaximumDistance () const; + float getRadialTileSize () const; + float getRadialTileBorder () const; + uint32 getRadialSeed () const; + float getFarRadialMinimumDistance () const; + float getFarRadialMaximumDistance () const; + float getFarRadialTileSize () const; + float getFarRadialTileBorder () const; + uint32 getFarRadialSeed () const; + float getTileWidthInMeters () const; + + bool getLegacyMap() const { return m_legacyMap; } + bool getLegacyMode() const { return m_legacyMode; } + + int getChunkOriginOffset() const { return m_chunkOriginOffset; } + int getChunkUpperPad() const { return m_chunkUpperPad; } + + const TerrainGenerator* getTerrainGenerator () const; + const BakedTerrain* getBakedTerrain () const; + + bool getWaterHeight (const Vector& position, float& height) const; + bool getWaterHeight (const Vector& position, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater = false) const; + TerrainGeneratorWaterType getWaterType (const Vector& position_w) const; + + // -- + + float getFloraTileWidthInMeters() const { return m_floraTileWidthInMeters; } + int getMapWidthInFlora() const { return m_mapWidthInFlora; } + int getStaticCollidableFloraFamily(int floraTileX, int floraTileY) const; + float getStaticCollidableFloraHeight(int floraTileX, int floraTileY) const; + +protected: + + struct RibbonQuad + { + TerrainGeneratorWaterType waterType; + Vector points[4]; + }; + + struct RibbonEndCap + { + TerrainGeneratorWaterType waterType; + Vector2d points[8]; + Rectangle2d extent; + float height; + }; + + struct WaterTable + { + TerrainGeneratorWaterType waterType; + const TerrainGenerator::Boundary* boundary; + float height; + }; + +protected: + + char* m_name; + float m_mapWidthInMeters; + float m_chunkWidthInMeters; + int m_numberOfTilesPerChunk; + bool m_useGlobalWaterTable; + float m_globalWaterTableHeight; + char* m_globalWaterTableShaderTemplateName; + float m_globalWaterTableShaderSize; + float m_environmentCycleTime; + float m_collidableMinimumDistance; + float m_collidableMaximumDistance; + float m_collidableTileSize; + float m_collidableTileBorder; + uint32 m_collidableSeed; + float m_nonCollidableMinimumDistance; + float m_nonCollidableMaximumDistance; + float m_nonCollidableTileSize; + float m_nonCollidableTileBorder; + uint32 m_nonCollidableSeed; + float m_radialMinimumDistance; + float m_radialMaximumDistance; + float m_radialTileSize; + float m_radialTileBorder; + uint32 m_radialSeed; + float m_farRadialMinimumDistance; + float m_farRadialMaximumDistance; + float m_farRadialTileSize; + float m_farRadialTileBorder; + uint32 m_farRadialSeed; + bool m_legacyMap; + + bool m_legacyMode; + const bool m_samplingMode; + + float m_tileWidthInMeters; + + int m_chunkOriginOffset; + int m_chunkUpperPad; + + TerrainGenerator* m_terrainGenerator; + BakedTerrain* m_bakedTerrain; + + typedef stdvector::fwd WaterTableList; + WaterTableList* m_waterTableList; + + typedef stdvector::fwd RibbonQuadList; + RibbonQuadList* m_ribbonQuadList; + + typedef stdvector::fwd RibbonEndCapList; + RibbonEndCapList* m_ribbonEndCapList; + + float m_floraTileWidthInMeters; + int m_mapWidthInFlora; + PackedIntegerMap *m_staticCollidableFloraMap; + PackedFixedPointMap *m_staticCollidableFloraHeightMap; + +protected: + + void load (Iff& iff); //lint !e1511 //-- member hides non-virtual member + void _load(Iff& iff, Tag version); + void createWaterTableAndRibbonQuadLists (); + void createWaterTableAndRibbonQuadLists (const TerrainGenerator::Layer* layer); + void _setSamplingParameters(bool legacyMode, int chunkOriginOffset, int chunkUpperPad); + void _setStaticCollidableFloraInfo(FloraGroup::Info *infoMap, float *heightMap); + void _destroyStaticCollidableFloraMaps(); + void _createDefaultStaticCollidableFloraMaps(); + +private: + + ProceduralTerrainAppearanceTemplate (); + ProceduralTerrainAppearanceTemplate (const ProceduralTerrainAppearanceTemplate&); + ProceduralTerrainAppearanceTemplate& operator= (const ProceduralTerrainAppearanceTemplate&); + + // ------------------------------------------------------------------ + +public: + + struct WriterData + { + public: + + const char* name; + float mapWidthInMeters; + float chunkWidthInMeters; + int numberOfTilesPerChunk; + bool useGlobalWaterTable; + float globalWaterTableHeight; + float globalWaterTableShaderSize; + const char* globalWaterTableShaderTemplateName; + float environmentCycleTime; + float collidableMinimumDistance; + float collidableMaximumDistance; + float collidableTileSize; + float collidableTileBorder; + uint32 collidableSeed; + float nonCollidableMinimumDistance; + float nonCollidableMaximumDistance; + float nonCollidableTileSize; + float nonCollidableTileBorder; + uint32 nonCollidableSeed; + float radialMinimumDistance; + float radialMaximumDistance; + float radialTileSize; + float radialTileBorder; + uint32 radialSeed; + float farRadialMinimumDistance; + float farRadialMaximumDistance; + float farRadialTileSize; + float farRadialTileBorder; + uint32 farRadialSeed; + bool legacyMap; + + // ------------------------------------ + + const TerrainGenerator *terrainGenerator; + const BakedTerrain *bakedTerrain; + const PackedIntegerMap *staticCollidableFloraMap; + const PackedFixedPointMap *staticCollidableFloraHeightMap; + + public: + + WriterData(); + }; + + void prepareWriterData(WriterData &writerData); + + static void write (Iff& iff, const WriterData& data); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.cpp new file mode 100644 index 00000000..5cf95df7 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.cpp @@ -0,0 +1,1498 @@ +//=================================================================== +// +// SamplerProceduralTerrainAppearance.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/SamplerProceduralTerrainAppearance.h" +#include "sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h" +#include "sharedTerrain/SamplerProceduralTerrainAppearance_Cache.h" + +#include "sharedCollision/BoxExtent.h" +#include "sharedCollision/CollideParameters.h" +#include "sharedCollision/CollisionInfo.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedMath/Plane.h" +#include "sharedMath/Line2d.h" +#include "sharedMath/Vector2d.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/Object.h" +#include "sharedTerrain/ProceduralTerrainAppearanceTemplate.h" +#include "sharedRandom/RandomGenerator.h" + +#include +#include +#include +#include +#include + +//=================================================================== + +namespace SamplerProceduralTerrainAppearanceNamespace +{ + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct TriangleIndirectionData + { + int offsetX0; + int offsetZ0; + int offsetX1; + int offsetZ1; + int offsetX2; + int offsetZ2; + }; + + static const int TRIANGLE_INDIRECTION_ARRAY_SIZE = 8; + + static const TriangleIndirectionData constructionTriangleIndirectionArray [TRIANGLE_INDIRECTION_ARRAY_SIZE] = + { + // x1, z1, x2, z2, x3, z3 + { 1, 1, 0, 2, 1, 2 }, + { 1, 1, 1, 2, 2, 2 }, + { 1, 1, 2, 2, 2, 1 }, + { 1, 1, 2, 1, 2, 0 }, + { 1, 1, 2, 0, 1, 0 }, + { 1, 1, 1, 0, 0, 0 }, + { 1, 1, 0, 0, 0, 1 }, + { 1, 1, 0, 1, 0, 2 } + }; + + static int chunkIndirectionArray [16] = + { + -1, 1, + 0, 1, + 1, 1, + -1, 0, + 1, 0, + -1, -1, + 0, -1, + 1, -1 + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class DenormalizedLine2d + { + public: + + DenormalizedLine2d (const Vector2d& point0, const Vector2d& point1) : + m_normal (-point1.y + point0.y, point1.x - point0.x), + m_c (-m_normal.dot (point0)) + { + } + + float computeDistanceTo (const Vector2d& point) const + { + return m_normal.dot (point) + m_c; + } + + private: + + DenormalizedLine2d (); + + private: + + Vector2d m_normal; + float m_c; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace SamplerProceduralTerrainAppearanceNamespace; + +// ---------------------------------------------------------------------- + +class SamplerProceduralTerrainAppearance::CollisionChunkSorter +{ +public: + + explicit CollisionChunkSorter(Vector const & position_o); + ~CollisionChunkSorter(); + CollisionChunkSorter(CollisionChunkSorter const &); + CollisionChunkSorter & operator=(CollisionChunkSorter const &); + + bool operator()(Chunk const * Chunk1, Chunk const * Chunk2) const; + +private: + + CollisionChunkSorter(); + +private: + + Vector m_position_o; +}; + +// ---------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::CollisionChunkSorter::CollisionChunkSorter(Vector const & position_o) : + m_position_o(position_o) +{ +} + +// ---------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::CollisionChunkSorter::~CollisionChunkSorter() +{ +} + +// ---------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::CollisionChunkSorter::CollisionChunkSorter(CollisionChunkSorter const & rhs) : + m_position_o(rhs.m_position_o) +{ +} + +// ---------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::CollisionChunkSorter & SamplerProceduralTerrainAppearance::CollisionChunkSorter::operator=(CollisionChunkSorter const & rhs) +{ + if (this != &rhs) + m_position_o = rhs.m_position_o; + + return *this; +} + +// ---------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::CollisionChunkSorter::operator()(Chunk const * const chunk1, Chunk const * const chunk2) const +{ + float const distanceSquaredToChunk1 = chunk1 ? m_position_o.magnitudeBetweenSquared(chunk1->getExtent()->getCenter()) : 0.f; + float const distanceSquaredToChunk2 = chunk2 ? m_position_o.magnitudeBetweenSquared(chunk2->getExtent()->getCenter()) : 0.f; + + return distanceSquaredToChunk1 < distanceSquaredToChunk2; +} + +//=================================================================== +// PUBLIC STATIC SamplerProceduralTerrainAppearance::SamplerChunk +//=================================================================== + +ArrayList* SamplerProceduralTerrainAppearance::SamplerChunk::ms_indexList; + +//------------------------------------------------------------------- + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITHOUT_INSTALL (SamplerProceduralTerrainAppearance::SamplerChunk, false, 256, 4, 0); + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::SamplerChunk::install () +{ + installMemoryBlockManager (); +} + +//---------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::SamplerChunk::compareTimestampsGreater(SamplerChunk const * const lhs, SamplerChunk const * const rhs) +{ + return lhs->m_timeStamp > rhs->m_timeStamp; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::SamplerChunk::createIndexList (const int numberOfTilesPerChunk, const int actualNumberOfPoles) +{ + const int size = sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE * 3; + ms_indexList = new ArrayList (size); + ms_indexList->preallocate (size, true); + + int indexIndex = 0; + + int x; + int z; + for (z = 0; z < numberOfTilesPerChunk; z++) + { + for (x = 0; x < numberOfTilesPerChunk; x++) + { + const int tileOriginX = x * 2; + const int tileOriginZ = z * 2; + + int i; + for (i = 0; i < TRIANGLE_INDIRECTION_ARRAY_SIZE; i++) + { + const int i0x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX0; + const int i0z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ0; + const int i0 = i0x + i0z * (actualNumberOfPoles); + + const int i1x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX1; + const int i1z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ1; + const int i1 = i1x + i1z * (actualNumberOfPoles); + + const int i2x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX2; + const int i2z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ2; + const int i2 = i2x + i2z * (actualNumberOfPoles); + + (*ms_indexList) [indexIndex++] = i0; + (*ms_indexList) [indexIndex++] = i1; + (*ms_indexList) [indexIndex++] = i2; + } + } + } +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::SamplerChunk::remove () +{ + removeMemoryBlockManager (); + + delete ms_indexList; + ms_indexList = 0; +} + +//=================================================================== +// PUBLIC SamplerProceduralTerrainAppearance::SamplerChunk +//=================================================================== + +SamplerProceduralTerrainAppearance::SamplerChunk::SamplerChunk (ProceduralTerrainAppearance& proceduralTerrainAppearance) : + Chunk (proceduralTerrainAppearance), + m_vertexList (0), + m_planeList (0), + m_timeStamp(time(0)) +{ +} + +//------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::SamplerChunk::~SamplerChunk () +{ + SamplerProceduralTerrainAppearance::Cache::destroyVertexList (m_vertexList); + m_vertexList = 0; + + SamplerProceduralTerrainAppearance::Cache::destroyPlaneList (m_planeList); + m_planeList = 0; + + SamplerProceduralTerrainAppearance::Cache::destroyShaderMap (shaderMap); + shaderMap = 0; + + SamplerProceduralTerrainAppearance::Cache::destroyFloraMap (m_floraStaticCollidableMap); + m_floraStaticCollidableMap = 0; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::SamplerChunk::getHeightAt (const Vector& pos, float* const height) const +{ + return getHeightAt (pos, height, 0); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::SamplerChunk::getHeightAt (const Vector& pos, float* const height, Vector* const normal) const +{ + // ------------------------------------------------ + // make sure we're in the chunk + const Vector vmin = m_boxExtent.getMin (); + const Vector vmax = m_boxExtent.getMax (); + if (pos.x < vmin.x || pos.x > vmax.x || pos.z < vmin.z || pos.z > vmax.z) + { + DEBUG_WARNING (true, ("called getHeightAt for position not within chunk")); + return false; + } + // ------------------------------------------------ + + // ------------------------------------------------ + // if the tile at x,z is excluded, return failure. + int tileX, tileZ; + _findTileXz(pos, tileX, tileZ); + if (isExcluded(tileX, tileZ)) + { + return false; + } + // ------------------------------------------------ + + + // ------------------------------------------------ + // construct vertical vector at x,z that goes + // from the highest point in the chunk to the + // lowest point in the chunk. + const Vector start (pos.x, vmax.y + 0.1f, pos.z); + const Vector end (pos.x, vmin.y - 0.1f, pos.z); + const Vector dir = end - start; + // ------------------------------------------------ + + //-- collide with the 8 polygons in the tile + bool found = false; + + CollisionInfo result; + result.setPoint (end); + + Vector intersection; + + const int numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + const int tileIndex = tileZ * numberOfTilesPerChunk + tileX; + const int triangleOffset = tileIndex * 8; + for (int tri = triangleOffset; tri < triangleOffset + 8; ++tri) + { + const Plane& plane = (*m_planeList) [tri]; + const Vector& normal = plane.getNormal (); + + if ( dir.dot(normal)<0.f // if triangle is facing upward + && plane.findIntersection(start, end, intersection) + ) + { + const int i0 = (*ms_indexList)[tri*3 + 0]; + const int i1 = (*ms_indexList)[tri*3 + 1]; + const int i2 = (*ms_indexList)[tri*3 + 2]; + + const Vector& v0 = (*m_vertexList)[i0]; + const Vector& v1 = (*m_vertexList)[i1]; + const Vector& v2 = (*m_vertexList)[i2]; + + DenormalizedLine2d const line01 (Vector2d (v0.x, v0.z), Vector2d (v1.x, v1.z)); + DenormalizedLine2d const line12 (Vector2d (v1.x, v1.z), Vector2d (v2.x, v2.z)); + DenormalizedLine2d const line20 (Vector2d (v2.x, v2.z), Vector2d (v0.x, v0.z)); + + if (line01.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line12.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line20.computeDistanceTo (Vector2d (start.x, start.z)) <= 0) + { + found = true; + + result.setPoint (intersection); + result.setNormal (normal); + } + } + } + + if (found) + { + if (height) + *height = result.getPoint ().y; + + if (normal) + *normal = result.getNormal (); + + return true; + } + + return false; +} + +//------------------------------------------------------------------- +#if 0 +bool SamplerProceduralTerrainAppearance::SamplerChunk::getHeightAt2(const Vector& pos, float* const height, Vector* const normal) const +{ + // ------------------------------------------------ + // make sure we're in the chunk + const Vector vmin = m_boxExtent.getMin (); + const Vector vmax = m_boxExtent.getMax (); + if (pos.x < vmin.x || pos.x > vmax.x || pos.z < vmin.z || pos.z > vmax.z) + { + DEBUG_WARNING (true, ("called getHeightAt for position not within chunk")); + return false; + } + // ------------------------------------------------ + + // ------------------------------------------------ + // get height pole and tile coordinate. + const Vector localPos = pos - vmin; + + const ProceduralTerrainAppearanceTemplate *proceduralTerrainAppearanceTemplate = getAppearanceTemplate(); + const float distanceBetweenPoles = proceduralTerrainAppearanceTemplate->getTileWidthInMeters() / 2.0f; + const int numberOfPolesPerChunk = proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk() * 2; + + int poleX = int(floor(localPos.x / distanceBetweenPoles)); + if (poleX>=numberOfPolesPerChunk) + { + poleX=numberOfPolesPerChunk-1; + } + + int poleZ = int(floor(localPos.z / distanceBetweenPoles)); + if (poleZ>=numberOfPolesPerChunk) + { + poleZ=numberOfPolesPerChunk-1; + } + + const int tileX = poleX>>1; + const int tileZ = poleZ>>1; + // ------------------------------------------------ + + // ------------------------------------------------ + // if the tile at x,z is excluded, return failure. + + // DEBUG + { + int dbgTileX, dbgTileZ; + _findTileXz(pos, dbgTileX, dbgTileZ); + DEBUG_FATAL(dbgTileX!=tileX, ("")); + DEBUG_FATAL(dbgTileZ!=tileZ, ("")); + } + + if (isExcluded(tileX, tileZ)) + { + return false; + } + // ------------------------------------------------ + + + // ------------------------------------------------ + // construct vertical vector at x,z that goes + // from the highest point in the chunk to the + // lowest point in the chunk. + const Vector start(pos.x, vmax.y + 0.1f, pos.z); + const Vector end(pos.x, vmin.y - 0.1f, pos.z); + const Vector dir = end - start; + // ------------------------------------------------ + + //-- collide with the 8 polygons in the tile + bool found = false; + + CollisionInfo result; + result.setPoint (end); + + Vector intersection; + + const int numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + const int tileIndex = tileZ * numberOfTilesPerChunk + tileX; + const int triangleOffset = tileIndex * 8; + for (int tri = triangleOffset; tri < triangleOffset + 8; ++tri) + { + const Plane& plane = (*m_planeList) [tri]; + const Vector& normal = plane.getNormal (); + + if ( dir.dot(normal)<0.f // if triangle is facing upward + && plane.findIntersection(start, end, intersection) + ) + { + const int i0 = (*ms_indexList)[tri*3 + 0]; + const int i1 = (*ms_indexList)[tri*3 + 1]; + const int i2 = (*ms_indexList)[tri*3 + 2]; + + const Vector& v0 = (*m_vertexList)[i0]; + const Vector& v1 = (*m_vertexList)[i1]; + const Vector& v2 = (*m_vertexList)[i2]; + + DenormalizedLine2d const line01 (Vector2d (v0.x, v0.z), Vector2d (v1.x, v1.z)); + DenormalizedLine2d const line12 (Vector2d (v1.x, v1.z), Vector2d (v2.x, v2.z)); + DenormalizedLine2d const line20 (Vector2d (v2.x, v2.z), Vector2d (v0.x, v0.z)); + + if (line01.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line12.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line20.computeDistanceTo (Vector2d (start.x, start.z)) <= 0) + { + found = true; + + result.setPoint (intersection); + result.setNormal (normal); + } + } + } + + if (found) + { + if (height) + *height = result.getPoint ().y; + + if (normal) + *normal = result.getNormal (); + + return true; + } + + return false; +} +#endif +//------------------------------------------------------------------- + +#define ALLOW_BACKFACING_COLLISION 0 + +bool SamplerProceduralTerrainAppearance::SamplerChunk::collide (const Vector& start, const Vector& end, CollideParameters const & /*collideParameters*/, CollisionInfo& result) const +{ + bool found = false; + + //-- test the line against the extent + if (m_boxExtent.testSphereOnly (start, end)) + { + NOT_NULL (m_vertexList); + NOT_NULL (m_planeList); + +#if ALLOW_BACKFACING_COLLISION == 0 + const Vector dir = end - start; +#endif + + Vector intersection; + + int const numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + for (int z = 0; z < numberOfTilesPerChunk; z++) + { + for (int x = 0; x < numberOfTilesPerChunk; x++) + { + if (isExcluded(x, z)) + continue; + + int const tileIndex = z * numberOfTilesPerChunk + x; + const int offset = tileIndex * 8; + + for (int k = offset; k < offset + 8; ++k) + { + const Plane& plane = (*m_planeList) [k]; + const Vector& normal = plane.getNormal (); + +#if ALLOW_BACKFACING_COLLISION == 0 + if ((dir.dot (normal) < 0.f) && (plane.findIntersection (start, end, intersection))) +#else + if (plane.findIntersection (start, end, intersection)) +#endif + { + const int i0 = (*ms_indexList) [k * 3 + 0]; + const int i1 = (*ms_indexList) [k * 3 + 1]; + const int i2 = (*ms_indexList) [k * 3 + 2]; + + const Vector& v0 = (*m_vertexList) [i0]; + const Vector& v1 = (*m_vertexList) [i1]; + const Vector& v2 = (*m_vertexList) [i2]; + + if ((start.magnitudeBetweenSquared (intersection) < start.magnitudeBetweenSquared (result.getPoint ())) && intersection.inPolygon (v0, v1, v2)) + { + found = true; + + result.setPoint (intersection); + result.setNormal (normal); + } + } + } + } + } + } + + return found; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::SamplerChunk::create (const ProceduralTerrainAppearance::CreateChunkData& createChunkData) +{ + createChunkData.validate (); + + chunkX = createChunkData.chunkX; + chunkZ = createChunkData.chunkZ; + chunkWidthInMeters = createChunkData.chunkWidthInMeters; + originOffset = createChunkData.originOffset; + numberOfPoles = createChunkData.numberOfPoles; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- cache and verify all variables from createChunkData + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const int numberOfTilesPerChunk = createChunkData.numberOfTilesPerChunk; + const int actualNumberOfPoles = (numberOfTilesPerChunk * 2) + 1; + + const Array2d* const ccd_shaderMap = &createChunkData.createChunkBuffer->shaderMap; + const Array2d* const ccd_floraStaticCollidableMap = &createChunkData.createChunkBuffer->floraStaticCollidableMap; + const Array2d* const ccd_excludeMap = &createChunkData.createChunkBuffer->excludeMap; + const Array2d* const ccd_passableMap = &createChunkData.createChunkBuffer->passableMap; + const Array2d* const vertexPositionMap = &createChunkData.createChunkBuffer->vertexPositionMap; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create the shared indexed triangle list if needed + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (!ms_indexList) + createIndexList (numberOfTilesPerChunk, actualNumberOfPoles); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- initialization + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_boxExtent.setMin(Vector::maxXYZ); + m_boxExtent.setMax(Vector::negativeMaxXYZ); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create and copy appropriate maps + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_vertexList = SamplerProceduralTerrainAppearance::Cache::createVertexList (sqr (actualNumberOfPoles)); + m_planeList = SamplerProceduralTerrainAppearance::Cache::createPlaneList (sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE); + shaderMap = SamplerProceduralTerrainAppearance::Cache::createShaderMap (numberOfPoles, numberOfPoles); + m_floraStaticCollidableMap = SamplerProceduralTerrainAppearance::Cache::createFloraMap (numberOfPoles, numberOfPoles); + + shaderMap->makeCopy (*ccd_shaderMap); + m_floraStaticCollidableMap->makeCopy (*ccd_floraStaticCollidableMap); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create vertex data + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + m_vertexList->clear (); + + for (int z = originOffset; z < originOffset + actualNumberOfPoles; z++) + { + for (int x = originOffset; x < originOffset + actualNumberOfPoles; x++) + { + m_vertexList->add (vertexPositionMap->getData (x,z)); + + m_boxExtent.updateMinAndMax (vertexPositionMap->getData (x,z)); + } + } + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- update extents + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_boxExtent.calculateCenterAndRadius(); + + Sphere boundingSphere = m_boxExtent.getSphere(); + boundingSphere.setRadius(boundingSphere.getRadius() + 0.001f); + m_boxExtent.setSphere(boundingSphere); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create triangles and planes + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + //-- todo index list is the same for every chunk + m_planeList->preallocate (sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE, true); + + int indexIndex = 0; + int planeIndex = 0; + + //-- iterate through tiles + for (int z = 0; z < numberOfTilesPerChunk; z++) + { + const int tileOriginZ = z * 2; // convert from tiles to height poles + for (int x = 0; x < numberOfTilesPerChunk; x++) + { + const int tileOriginX = x * 2; // convert from tiles to height poles + + if (!ccd_passableMap->getData(tileOriginX + originOffset, tileOriginZ + originOffset)) + { + setPassable(x, z, false); + } + + if (ccd_excludeMap->getData (tileOriginX + originOffset, tileOriginZ + originOffset)) + { + _setExcluded(x, z); + continue; + } + + for (int i = 0; i < TRIANGLE_INDIRECTION_ARRAY_SIZE; i++) + { + const int i0 = (*ms_indexList)[indexIndex++]; + const int i1 = (*ms_indexList)[indexIndex++]; + const int i2 = (*ms_indexList)[indexIndex++]; + + (*m_planeList)[planeIndex++].set((*m_vertexList)[i0], (*m_vertexList)[i1], (*m_vertexList)[i2]); + } + } + } + } +} + +//------------------------------------------------------------------- + +int SamplerProceduralTerrainAppearance::SamplerChunk::getChunkMemorySize () const +{ + const int geometrySize = sizeof (Vector) * m_vertexList->getNumberOfElements (); + const int planeSize = sizeof (Plane) * m_planeList->getNumberOfElements (); + +#ifdef _DEBUG + DEBUG_REPORT_PRINT (true, (" geometrySize = %i\n", geometrySize)); + DEBUG_REPORT_PRINT (true, (" planeSize = %i\n", planeSize)); +#endif + + return Chunk::getChunkMemorySize () + sizeof (*this) + geometrySize + planeSize; +} + +//=================================================================== +// PUBLIC SamplerProceduralTerrainAppearance +//=================================================================== + +SamplerProceduralTerrainAppearance::SamplerProceduralTerrainAppearance (SamplerProceduralTerrainAppearanceTemplate* appearanceTemplate) : + ProceduralTerrainAppearance (appearanceTemplate), + terrainSamplerTemplate(*appearanceTemplate), + m_chunkMap (new ChunkMap), + m_chunkMapKeyOffset (0), + m_highUsedChunkList (new SamplerChunkList), + m_lowUsedChunkList (new SamplerChunkList), + m_unusedChunkList (new SamplerChunkList), + m_invalidateChunkList (new ChunkList) +{ + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- to ensure that memory isn't claimed on the client for server terrain (this must be first) + { + Cache::install (); + SamplerChunk::install (); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + const_cast (appearanceTemplate->getTerrainGenerator ()->getShaderGroup ()).loadSurfaceProperties (); + + const float mapWidthInMeters = proceduralTerrainAppearanceTemplate->getMapWidthInMeters(); + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + const int numberOfTilesPerChunk = proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk (); + const int actualNumberOfPoles = (numberOfTilesPerChunk * 2) + 1; + Cache::warm (sqr (actualNumberOfPoles), sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE, numberOfPoles); + + m_chunkMapKeyOffset = static_cast (mapWidthInMeters / chunkWidthInMeters); +} + +//------------------------------------------------------------------- + +SamplerProceduralTerrainAppearance::~SamplerProceduralTerrainAppearance () +{ + while (!m_chunkMap->empty ()) + { + ChunkMap::iterator iter = m_chunkMap->begin (); + + delete iter->second; + m_chunkMap->erase (iter); + } + + delete m_chunkMap; + delete m_highUsedChunkList; + delete m_lowUsedChunkList; + delete m_unusedChunkList; + delete m_invalidateChunkList; + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- to ensure that memory isn't claimed on the client for server terrain (this must be last) + { + SamplerChunk::remove (); + Cache::remove (); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +//------------------------------------------------------------------- + +float SamplerProceduralTerrainAppearance::alter (float time) +{ + PROFILER_AUTO_BLOCK_DEFINE("SamplerProceduralTerrainAppearance::alter"); + + int i; + for (i = 0; i < getNumberOfReferenceObjects (); i++) + { + const Object* const object = getReferenceObject (i); + if (object->isInWorldCell ()) + ProceduralTerrainAppearance::createChunk (getOwner ()->rotateTranslate_w2o (object->getPosition_w ()), 1); + } + + IGNORE_RETURN (ProceduralTerrainAppearance::alter (time)); + + // @todo figure out what this should floatly return. + return AlterResult::cms_alterNextFrame; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::render () const +{ + DEBUG_FATAL (true, ("SamplerProceduralTerrainAppearance::render should not be called")); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::hasHighLevelOfDetailTerrain (const Vector& position_o) const +{ + return ProceduralTerrainAppearance::findChunk (position_o, 1) != 0; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::generateBetween(Vector const & start_o, Vector const & end_o, ChunkList & chunkList) +{ + int startX = calculateChunkX(start_o.x); + int startZ = calculateChunkZ(start_o.z); + int endX = calculateChunkX(end_o.x); + int endZ = calculateChunkZ(end_o.z); + + // if both sets of indices are invalid, we don't want to waste time trying to generate chunks + // if only one is invalid, we still want to check the valid chunks on the terrain from the valid point + if (!areValidChunkIndices(startX, startZ) && !areValidChunkIndices(endX, endZ)) + return; + + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + typedef std::vector > GenerateList; + GenerateList generateList; + + if (startX == endX && startZ == endZ) + { + // if we are in the same chunk, just add it and be done with it + generateList.push_back(GenerateList::value_type(startX, startZ)); + } + else if (fabs(start_o.x - end_o.x) < 0.00001f && fabs(start_o.z - end_o.z) < 0.00001f) + { + // this is to not cause a debug_fatal on line2d construction + generateList.push_back(GenerateList::value_type(startX, startZ)); + generateList.push_back(GenerateList::value_type(endX, endZ)); + } + // we only want to do the complicated calculations on the shorter side + else if (abs(endX - startX) < abs(endZ - startZ)) + { + Line2d const line(start_o.x, start_o.z, end_o.x, end_o.z); + + // in order to make the boundary checks, we reorder the points so that startX <= endX + if (startX > endX) + { + std::swap(startX, endX); + std::swap(startZ, endZ); + } + + // this is the X value of the edge (parallel to the X axis) we will cross on our way to endX, this changes as we go through the loop + float boundingChunkEdgeX = (startX+1)*chunkWidthInMeters; + int subStartZ = startZ; + int subEndZ = endZ; + + for (int x = startX; x <= endX; ++x) + { + // if we are on the last X, we need to generate until endZ + if (x == endX) + subEndZ = endZ; + else + { + // we want to find out how far along on the X axis we need to generate chunks (subStartZ -> subEndZ) + // in these vectors, the y is our z here, since we are working in a 2d space + Vector2d intersect; + if (line.findIntersection(Vector2d(boundingChunkEdgeX, start_o.z), Vector2d(boundingChunkEdgeX, end_o.z), intersect)) + subEndZ = calculateChunkZ(intersect.y); + else + DEBUG_WARNING (true, ("SamplerProceduralTerrainAppearance::did not intersect with boundingChunkX while generating chunks: startX %i, endX %i, startZ %i, endZ %i, boundingEdgeX %f", startX, endX, startZ, endZ, boundingChunkEdgeX)); + } + + // generate all chunks along the x axis that we need (inclusive of subStartZ and subEndZ) + int deltaZ = (subStartZ < subEndZ) ? 1 : -1; + for (int z = subStartZ; z != subEndZ; z += deltaZ) + generateList.push_back(GenerateList::value_type(x, z)); + generateList.push_back(GenerateList::value_type(x, subEndZ)); + + // along the next X axis (moves b/c of the for loop) we start at the endZ of this run + subStartZ = subEndZ; + + // move the boundingEdge to where it should be for the next loop + boundingChunkEdgeX += chunkWidthInMeters; + } + } + else + { + Line2d const line(start_o.x, start_o.z, end_o.x, end_o.z); + + // in order to make the boundary checks, we reorder the points so that startZ <= endZ + if (startZ > endZ) + { + std::swap(startX, endX); + std::swap(startZ, endZ); + } + + // this is the Z value of the edge (parallel to the Z axis) we will cross on our way to endZ, this changes as we go through the loop + float boundingChunkEdgeZ = (startZ+1)*chunkWidthInMeters; + int subStartX = startX; + int subEndX = endX; + + for (int z = startZ; z <= endZ; ++z) + { + // if we are on the last Z, we need to generate until endZ + if (z == endZ) + subEndX = endX; + else + { + // we want to find out how far along on the Z axis we need to generate chunks (subStartX -> subEndX) + Vector2d intersect; + if (line.findIntersection(Vector2d(start_o.x, boundingChunkEdgeZ), Vector2d(end_o.x, boundingChunkEdgeZ), intersect)) + subEndX = calculateChunkX(intersect.x); + else + DEBUG_WARNING (true, ("SamplerProceduralTerrainAppearance::did not intersect with boundingChunkZ while generating chunks: startX %i, endX %i, startZ %i, endZ %i, boundingEdgeZ %f", startX, endX, startZ, endZ, boundingChunkEdgeZ)); + } + + // generate all chunks along this z axis that we need (inclusive of subStartX and subEndX) + int deltaX = (subStartX < subEndX) ? 1 : -1; + for (int x = subStartX; x != subEndX; x += deltaX) + generateList.push_back(GenerateList::value_type(x, z)); + generateList.push_back(GenerateList::value_type(subEndX, z)); + + // along the next Z axis (moves b/c of the for loop) we start at the endX of this run + subStartX = subEndX; + + // move the boundingEdge to where it should be for the next loop + boundingChunkEdgeZ += chunkWidthInMeters; + } + } + + // add on all chunks to be generated to chunkList. if we encounter invalid chunks (null), don't include them + const Chunk* chunk; + for (GenerateList::iterator iter = generateList.begin(); iter != generateList.end(); ++iter) + { + createChunk(iter->first, iter->second, 1, 0); + chunk = findChunk(iter->first, iter->second, 1); + + if (chunk) + chunkList.push_back(chunk); + } +} + +//=================================================================== +// PROTECTED SamplerProceduralTerrainAppearance +//=================================================================== +//------------------------------------------------------------------- +static int calculateFloraTileX (const Vector& position, const float tileWidthInMeters) +{ + const int x = static_cast ((position.x >= 0.f) ? floorf (position.x / tileWidthInMeters) : ceilf (position.x / tileWidthInMeters)); + + //-- zero is not a valid chunk index + return (position.x < 0.f) ? x - 1 : x; +} + +//------------------------------------------------------------------- + +static int calculateFloraTileZ (const Vector& position, const float tileWidthInMeters) +{ + const int z = static_cast ((position.z >= 0.f) ? floorf (position.z / tileWidthInMeters) : ceilf (position.z / tileWidthInMeters)); + + //-- zero is not a valid chunk index + return (position.z < 0.f) ? z - 1 : z; +} + +//------------------------------------------------------------------- + +static uint32 calculateFloraMapKey (const int x, const int z, const int mapWidthInTiles) +{ + DEBUG_FATAL (x < 0, ("")); + DEBUG_FATAL (z < 0, ("")); + return static_cast (z * mapWidthInTiles + x); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::isStaticCollidableFloraChunk(const int x, const int z, const int chunkSize) +{ + //-- make sure indices are valid + if (!areValidChunkIndices (x, z)) + { + return false; + } + + //-- see if the chunk already exists + if (findChunk (x, z, chunkSize) != 0) + { + return false; + } + + const float floraTileWidthInMeters = 16.f; + const float floraTileBorderInMeters = proceduralTerrainAppearanceTemplate->getCollidableTileBorder (); + const int floraMapWidthInTiles = static_cast (getMapWidthInMeters () / floraTileWidthInMeters); + const int floraTileCenterOffset = floraMapWidthInTiles / 2; + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + Rectangle2d extent2d; + extent2d.x0 = static_cast(x)*chunkWidthInMeters; + extent2d.y0 = static_cast(z)*chunkWidthInMeters; + extent2d.x1 = extent2d.x0 + chunkWidthInMeters; + extent2d.y1 = extent2d.y0 + chunkWidthInMeters; + + const Vector start(extent2d.x0 + chunkWidthInMeters/2, 0, extent2d.y0 + chunkWidthInMeters/2); + + const int floraTileX = calculateFloraTileX (start, floraTileWidthInMeters); + const int floraTileZ = calculateFloraTileZ (start, floraTileWidthInMeters); + const int keyX = floraTileX + floraTileCenterOffset; + const int keyZ = floraTileZ + floraTileCenterOffset; + const uint32 key = calculateFloraMapKey (keyX, keyZ, floraMapWidthInTiles); + + const FloraGroup::Info fgi = terrainSamplerTemplate.getStaticCollidableFloraSamples()[key]; + if (!fgi.getFamilyId()) + { + RandomGenerator random (key); + + const float xOffset = random.randomReal (0.f, 1.f); + const float zOffset = random.randomReal (0.f, 1.f); + + const Vector floraTileStart (static_cast (floraTileX) * floraTileWidthInMeters, 0.f, static_cast (floraTileZ) * floraTileWidthInMeters); + const Vector floraPositionWithinTile (xOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters, 0.f, zOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters); + + Vector floraPosition = floraTileStart + floraPositionWithinTile; + if (extent2d.isWithin(floraPosition.x, floraPosition.z)) + { + return true; + } + } + + return false; +} + +void SamplerProceduralTerrainAppearance::createChunk (int x, int z, int chunkSize, unsigned) +{ + createChunk(x, z, chunkSize); +} + +SamplerProceduralTerrainAppearance::SamplerChunk *SamplerProceduralTerrainAppearance::createChunk (const int x, const int z, const int chunkSize) +{ + //-- make sure indices are valid + if (!areValidChunkIndices (x, z)) + return 0; + + //-- see if the chunk already exists + if (findChunk (x, z, chunkSize) != 0) + return 0; + + const TerrainGenerator* terrainGenerator = proceduralTerrainAppearanceTemplate->getTerrainGenerator (); + const int numberOfTilesPerChunk = proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk (); + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + const float tileWidthInMeters = proceduralTerrainAppearanceTemplate->getTileWidthInMeters (); + + //-- chunk does not exist -- it needs to be created. find out what map data i'll need to ask the generator for + const float distanceBetweenPoles = tileWidthInMeters * 0.5f; + + const Vector start ( + static_cast (x) * chunkWidthInMeters - static_cast (originOffset) * distanceBetweenPoles, + 0.0f, + static_cast (z) * chunkWidthInMeters - static_cast (originOffset) * distanceBetweenPoles + ); + + SamplerChunk* chunk = new SamplerChunk (*this); + + //-- setup data needed to create a chunk + ProceduralTerrainAppearance::CreateChunkData createChunkData (&createChunkBuffer); + + createChunkData.chunkX = x; + createChunkData.chunkZ = z; + createChunkData.start = start; + createChunkData.numberOfTilesPerChunk = numberOfTilesPerChunk; + createChunkData.chunkWidthInMeters = chunkWidthInMeters; + createChunkData.tileWidthInMeters = tileWidthInMeters; + createChunkData.shaderGroup = &terrainGenerator->getShaderGroup (); + createChunkData.floraGroup = &terrainGenerator->getFloraGroup (); + createChunkData.radialGroup = &terrainGenerator->getRadialGroup (); + createChunkData.environmentGroup = &terrainGenerator->getEnvironmentGroup (); + createChunkData.fractalGroup = &terrainGenerator->getFractalGroup (); + createChunkData.bitmapGroup = &terrainGenerator->getBitmapGroup (); + createChunkData.originOffset = originOffset; + createChunkData.numberOfPoles = numberOfPoles; + + //-- ask the generator to fill out this area + TerrainGenerator::GeneratorChunkData generatorChunkData(proceduralTerrainAppearanceTemplate->getLegacyMode()); + + generatorChunkData.heightMap = &createChunkData.createChunkBuffer->heightMap; + generatorChunkData.colorMap = &createChunkData.createChunkBuffer->colorMap; + generatorChunkData.shaderMap = &createChunkData.createChunkBuffer->shaderMap; + generatorChunkData.floraStaticCollidableMap = &createChunkData.createChunkBuffer->floraStaticCollidableMap; + generatorChunkData.floraStaticNonCollidableMap = &createChunkData.createChunkBuffer->floraStaticNonCollidableMap; + generatorChunkData.floraDynamicNearMap = &createChunkData.createChunkBuffer->floraDynamicNearMap; + generatorChunkData.floraDynamicFarMap = &createChunkData.createChunkBuffer->floraDynamicFarMap; + generatorChunkData.environmentMap = &createChunkData.createChunkBuffer->environmentMap; + generatorChunkData.vertexPositionMap = &createChunkData.createChunkBuffer->vertexPositionMap; + generatorChunkData.vertexNormalMap = &createChunkData.createChunkBuffer->vertexNormalMap; + generatorChunkData.excludeMap = &createChunkData.createChunkBuffer->excludeMap; + generatorChunkData.passableMap = &createChunkData.createChunkBuffer->passableMap; + generatorChunkData.start = start; + generatorChunkData.originOffset = originOffset; + generatorChunkData.numberOfPoles = numberOfPoles; + generatorChunkData.upperPad = upperPad; + generatorChunkData.distanceBetweenPoles = distanceBetweenPoles; + generatorChunkData.shaderGroup = &terrainGenerator->getShaderGroup (); + generatorChunkData.floraGroup = &terrainGenerator->getFloraGroup (); + generatorChunkData.radialGroup = &terrainGenerator->getRadialGroup (); + generatorChunkData.environmentGroup = &terrainGenerator->getEnvironmentGroup (); + generatorChunkData.fractalGroup = &terrainGenerator->getFractalGroup (); + generatorChunkData.bitmapGroup = &terrainGenerator->getBitmapGroup (); + + terrainGenerator->generateChunk (generatorChunkData); + + //-- create the chunk using the data the generator created + chunk->create (createChunkData); + createFlora (chunk); + + addChunk (chunk, chunkSize); + + return chunk; +} //lint !e429 //-- chunk has not been freed or returned + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::createFlora (const Chunk* const chunk) +{ + NOT_NULL (chunk); + +// const TerrainGenerator* generator = appearanceTemplate->getTerrainGenerator (); +// const float collidableMinimumDistance = appearanceTemplate->getCollidableMinimumDistance (); +// const float collidableMaximumDistance = appearanceTemplate->getCollidableMaximumDistance (); +// const float collidableTileSize = appearanceTemplate->getCollidableTileSize (); +// const float collidableTileBorder = appearanceTemplate->getCollidableTileBorder (); +// const uint32 collidableSeed = appearanceTemplate->getCollidableSeed (); + + const float floraTileWidthInMeters = 16.f; + const float floraTileBorderInMeters = proceduralTerrainAppearanceTemplate->getCollidableTileBorder (); + const int floraMapWidthInTiles = static_cast (getMapWidthInMeters () / floraTileWidthInMeters); + const int floraTileCenterOffset = floraMapWidthInTiles / 2; + + const BoxExtent& extent = chunk->getBoxExtent (); + const Vector start = Vector::linearInterpolate (extent.getMin (), extent.getMax (), 0.5f); + const int floraTileX = calculateFloraTileX (start, floraTileWidthInMeters); + const int floraTileZ = calculateFloraTileZ (start, floraTileWidthInMeters); + const int keyX = floraTileX + floraTileCenterOffset; + const int keyZ = floraTileZ + floraTileCenterOffset; + const uint32 key = calculateFloraMapKey (keyX, keyZ, floraMapWidthInTiles); + + const FloraGroup::Info fgi = terrainSamplerTemplate.getStaticCollidableFloraSamples()[key]; + if (!fgi.getFamilyId()) + { + RandomGenerator random (key); + + const float xOffset = random.randomReal (0.f, 1.f); + const float zOffset = random.randomReal (0.f, 1.f); + + const Vector floraTileStart (static_cast (floraTileX) * floraTileWidthInMeters, 0.f, static_cast (floraTileZ) * floraTileWidthInMeters); + const Vector floraPositionWithinTile (xOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters, 0.f, zOffset * (floraTileWidthInMeters - (2.f * floraTileBorderInMeters)) + floraTileBorderInMeters); + + const Rectangle2d extent2d (extent.getLeft (), extent.getBack (), extent.getRight (), extent.getFront ()); + + Vector floraPosition = floraTileStart + floraPositionWithinTile; + + if ( extent2d.isWithin (floraPosition.x, floraPosition.z) + && !chunk->isExcluded(floraPosition) + //&& chunk->getHeightAt (floraPosition, &floraPosition.y) + ) + { + FloraGroup::Info data; + bool floraAllowed; + if (chunk->findStaticCollidableFlora (floraPosition, data, floraAllowed)) + { + if (data.getFamilyId()) + { + if (chunk->getHeightAt(floraPosition, &floraPosition.y)) + { + terrainSamplerTemplate.setFloraTileSample(key, data, floraPosition.y); + } + } + } + } + } +} + +void SamplerProceduralTerrainAppearance::SamplerChunk::writeChunkData (const char* filename) const +{ + FILE* outfile = fopen (filename, "wt"); + if (!outfile) + return; + + NOT_NULL (m_vertexList); + + int i; + for (i = 0; i < m_vertexList->getNumberOfElements (); i++) + { + Vector v = (*m_vertexList) [i]; + + fprintf (outfile, "%4i <%5.1f, %5.1f, %5.1f>\n", i, v.x, v.y, v.z); + } + + fclose (outfile); +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::writeChunkData (int chunkX, int chunkZ) const +{ + //-- create chunk + const_cast (this)->createChunk (chunkX, chunkZ, 1, 0); + + //-- get chunk + const SamplerChunk* chunk = dynamic_cast (findChunk (chunkX, chunkZ, 1)); + NOT_NULL (chunk); + + //-- write chunk + char filename [100]; + sprintf (filename, "%3i_%3i.txt", chunkX, chunkZ); + chunk->writeChunkData (filename); +} + +//------------------------------------------------------------------- + +int SamplerProceduralTerrainAppearance::getTerrainType (const Vector& position_o) const +{ + Vector result = position_o; + float waterHeight; + if (getHeight (position_o, result.y) && getWaterHeight (position_o, waterHeight) && result.y < waterHeight) + return 1; + + return 0; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::invalidateRegion (const Rectangle2d& extent2d) +{ + m_invalidateChunkList->clear (); + + //-- figure out which chunks we need to invalidate + { + ChunkMap::iterator iter = m_chunkMap->begin (); + ChunkMap::iterator end = m_chunkMap->end (); + for (; iter != end; ++iter) + { + const Chunk* const chunk = iter->second; + const BoxExtent& boxExtent = chunk->getBoxExtent (); + const Rectangle2d chunkExtent2d (boxExtent.getMin ().x, boxExtent.getMin ().z, boxExtent.getMax ().x, boxExtent.getMax ().z); + if (extent2d.intersects (chunkExtent2d)) + m_invalidateChunkList->push_back (chunk); + } + } + + //-- delete those chunks + { + while (!m_invalidateChunkList->empty ()) + { + const Chunk* const chunk = m_invalidateChunkList->back (); + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + delete iter->second; + m_chunkMap->erase (iter); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + m_invalidateChunkList->pop_back (); + } + } +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::removeUnnecessaryChunk () +{ + //-- figure out which high chunks are in use + { + m_highUsedChunkList->clear (); + m_highUsedChunkList->reserve (static_cast (getNumberOfReferenceObjects ())); + + int i; + for (i = 0; i < getNumberOfReferenceObjects (); ++i) + { + const Object* const object = getReferenceObject (i); + if (object->isInWorld () && object->isInWorldCell ()) + { + const Vector& position = object->getPosition_w (); + const SamplerChunk* const chunk = safe_cast(ProceduralTerrainAppearance::findChunk (position, 1)); + if (chunk) + m_highUsedChunkList->push_back (chunk); + } + } + + std::sort (m_highUsedChunkList->begin (), m_highUsedChunkList->end ()); + SamplerChunkList::iterator iter = std::unique (m_highUsedChunkList->begin (), m_highUsedChunkList->end ()); + IGNORE_RETURN (m_highUsedChunkList->erase (iter, m_highUsedChunkList->end ())); + } + + //-- figure out which low chunks are in use + { + m_lowUsedChunkList->clear (); + m_lowUsedChunkList->reserve (m_highUsedChunkList->size () * 8); + + uint i; + for (i = 0; i < m_highUsedChunkList->size (); ++i) + { + const SamplerChunk* const chunk = (*m_highUsedChunkList) [i]; + const int chunkX = chunk->getChunkX (); + const int chunkZ = chunk->getChunkZ (); + + int j; + for (j = 0; j < 8; ++j) + { + const SamplerChunk* const lowChunk = safe_cast(findChunk (chunkX + chunkIndirectionArray [j * 2 + 0], chunkZ + chunkIndirectionArray [j * 2 + 1], 1)); + if (lowChunk && !std::binary_search (m_highUsedChunkList->begin (), m_highUsedChunkList->end (), lowChunk)) + m_lowUsedChunkList->push_back (lowChunk); + } + } + + std::sort (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end ()); + SamplerChunkList::iterator iter = std::unique (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end ()); + IGNORE_RETURN (m_lowUsedChunkList->erase (iter, m_lowUsedChunkList->end ())); + } + + //-- iterate through the tree and delete chunks not in use + { + m_unusedChunkList->clear (); + m_unusedChunkList->reserve (static_cast (getNumberOfChunks ())); + + ChunkMap::iterator iter = m_chunkMap->begin (); + ChunkMap::iterator end = m_chunkMap->end (); + for (; iter != end; ++iter) + { + const SamplerChunk* const chunk = safe_cast(iter->second); + + if (!std::binary_search (m_highUsedChunkList->begin (), m_highUsedChunkList->end (), chunk) && + !std::binary_search (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end (), chunk) + ) + m_unusedChunkList->push_back (chunk); + } + } + + //-- sort the unused chunks by timestamp so the oldest ones get deleted first + std::sort(m_unusedChunkList->begin(), m_unusedChunkList->end(), SamplerChunk::compareTimestampsGreater); + + //-- can I delete at least 10 unused Chunks? + int chunksToDelete = 128; + while (chunksToDelete > 0 && !m_unusedChunkList->empty ()) + { + const Chunk* const chunk = m_unusedChunkList->back (); + NOT_NULL (chunk); + + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + DEBUG_FATAL (chunk != iter->second, ("chunk in unused chunklist does not match chunk found in chunkmap")); + + // we don't need to check if this is in the chunksCreatedThisFrame, + // the unusedChunkList was created w/ the condition that it's elements were not created this frame (see above) + delete iter->second; + m_chunkMap->erase (iter); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + m_unusedChunkList->pop_back (); + --chunksToDelete; + } + + if (chunksToDelete > 0) + { + //-- sort the low chunks by timestamp so the oldest ones get deleted first + std::sort(m_lowUsedChunkList->begin(), m_lowUsedChunkList->end(), SamplerChunk::compareTimestampsGreater); + + while (chunksToDelete > 0 && !m_lowUsedChunkList->empty ()) + { + const Chunk* const chunk = m_lowUsedChunkList->back (); + NOT_NULL (chunk); + + // only delete this chunk if it was not created in this frame + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + DEBUG_FATAL (chunk != iter->second, ("chunk in unused chunklist does not match chunk found in chunkmap")); + + delete iter->second; + m_chunkMap->erase (iter); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + --chunksToDelete; + + m_lowUsedChunkList->pop_back (); + } + } +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::addChunk (Chunk* const chunk, const int /*chunkSize*/) +{ + const uint32 key = computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ()); + + bool result = m_chunkMap->insert (std::make_pair (key, chunk)).second; + UNREF (result); + DEBUG_FATAL (!result, ("")); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::collideChunkList(ChunkList const & chunkList, Vector const & start_o, Vector const & end_o, CollisionInfo& result) const +{ + bool collided = false; + + result.setPoint (end_o); + + //-- fire ray through chunks + for (ChunkList::const_iterator iter = chunkList.begin (); iter != chunkList.end (); ++iter) + { + Chunk const * const chunk = *iter; + + CollisionInfo info; + if (chunk->collide (start_o, result.getPoint (), CollideParameters::cms_default, info)) + { + collided = true; + result = info; + } + } + + return collided; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::collide(Vector const & start_o, Vector const & end_o, CollideParameters const & /*collideParameters*/, CollisionInfo & result) const +{ + ChunkList chunkList; + std::stable_sort(chunkList.begin(), chunkList.end(), CollisionChunkSorter(start_o)); + + return collideChunkList(chunkList, start_o, end_o, result); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearance::collideForceChunkCreation(Vector const & start_o, Vector const & end_o, CollisionInfo & result) +{ + ChunkList chunkList; + generateBetween(start_o, end_o, chunkList); + std::stable_sort(chunkList.begin(), chunkList.end(), CollisionChunkSorter(start_o)); + + return collideChunkList(chunkList, start_o, end_o, result); +} + +//------------------------------------------------------------------- + +int SamplerProceduralTerrainAppearance::getNumberOfChunks () const +{ + return static_cast (m_chunkMap->size ()); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* SamplerProceduralTerrainAppearance::findChunk (const int x, const int z, const int /*chunkSize*/) const +{ + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (x, z)); + if (iter != m_chunkMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* SamplerProceduralTerrainAppearance::findFirstRenderableChunk (const int x, const int z) const +{ + return findChunk (x, z, 1); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* SamplerProceduralTerrainAppearance::findAnyChunk () const +{ + if (m_chunkMap->empty ()) + return 0; + + return m_chunkMap->begin ()->second; +} + +//------------------------------------------------------------------- + +uint32 SamplerProceduralTerrainAppearance::computeChunkMapKey (const int x, const int z) const +{ + return ((x + m_chunkMapKeyOffset) & 0x0FFFF) << 16 | ((z + m_chunkMapKeyOffset) & 0x0FFFF); +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::prepareForDelete (Chunk const * const chunk) +{ + ProceduralTerrainAppearance::prepareForDelete (chunk); +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::purgeChunks() +{ + while (!m_chunkMap->empty ()) + { + ChunkMap::iterator iter = m_chunkMap->begin (); + + delete iter->second; + m_chunkMap->erase (iter); + } +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.h new file mode 100644 index 00000000..984e894c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance.h @@ -0,0 +1,158 @@ +//=================================================================== +// +// SamplerProceduralTerrainAppearance.h +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_SamplerProceduralTerrainAppearance_h +#define INCLUDED_SamplerProceduralTerrainAppearance_h + +//=================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" + +class Plane; +class MemoryBlockManager; + +//=================================================================== +class SamplerProceduralTerrainAppearanceTemplate; + +class SamplerProceduralTerrainAppearance : public ProceduralTerrainAppearance +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Chunk defines a chunk of terrain in the terrain system + // + class SamplerChunk : public ProceduralTerrainAppearance::Chunk + { + MEMORY_BLOCK_MANAGER_INTERFACE_WITHOUT_INSTALL; + + protected: + + // indexList is a list of triplets indexing the vertex positions used in each triangle of the chunk. + static ArrayList* ms_indexList; + + protected: + + // vertexList is a list of 3D positions for the chunk's height poles. size is (numberOfHeightPoles-2)^2 + ArrayList* m_vertexList; + + // planeList is a list of planes corresponding to the above triangles + ArrayList* m_planeList; + + time_t m_timeStamp; + + private: + + static void createIndexList (int numberOfTilesPerChunk, int actualNumberOfPoles); + + private: + + SamplerChunk (); + SamplerChunk (const SamplerChunk& rhs); + SamplerChunk& operator= (const SamplerChunk& rhs); + + public: + + static void install (); + static void remove (); + static bool compareTimestampsGreater(SamplerChunk const * lhs, SamplerChunk const * rhs); + + public: + + explicit SamplerChunk (ProceduralTerrainAppearance& proceduralTerrainAppearance); + virtual ~SamplerChunk (); + + virtual bool getHeightAt (const Vector& worldPos, float* height) const; + virtual bool getHeightAt (const Vector& worldPos, float* height, Vector* normal) const; + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + virtual int getChunkMemorySize () const; + + void create (const ProceduralTerrainAppearance::CreateChunkData& newCreateChunkData); + + void writeChunkData (const char* filename) const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Cache; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + + SamplerProceduralTerrainAppearance (SamplerProceduralTerrainAppearanceTemplate* appearanceTemplate); + virtual ~SamplerProceduralTerrainAppearance (); + + virtual float alter (float time); + virtual void render () const; + virtual void writeChunkData (int chunkX, int chunkZ) const; + virtual int getTerrainType (const Vector& position_o) const; + virtual void invalidateRegion (const Rectangle2d& extent2d); + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + virtual bool collideForceChunkCreation (Vector const & start_o, Vector const & end_o, CollisionInfo & result); + virtual int getNumberOfChunks () const; + virtual bool hasHighLevelOfDetailTerrain (const Vector& position_o) const; + + bool isStaticCollidableFloraChunk(const int x, const int z, const int chunkSize); + + SamplerChunk *createChunk(const int x, const int z, const int chunkSize); + virtual void createChunk (int x, int z, int chunkSize, unsigned hasLargerNeighborFlags); + virtual void purgeChunks(); + + void createFlora (const Chunk* const chunk); + +protected: + + typedef stdmap::fwd ChunkMap; + typedef stdvector::fwd ChunkList; + typedef stdvector::fwd SamplerChunkList; + typedef stdset::fwd ChunkSet; + +protected: + + virtual void removeUnnecessaryChunk (); + virtual void addChunk (Chunk* chunk, int chunkSize); + virtual const Chunk* findChunk (int x, int z, int chunkSize) const; + virtual const Chunk* findFirstRenderableChunk (int x, int z) const; + virtual const Chunk* findAnyChunk () const; + virtual uint32 computeChunkMapKey (int x, int z) const; + virtual void prepareForDelete (Chunk const * chunk); + void generateBetween(Vector const & start_o, Vector const & end_o, ChunkList & chunkList); + bool collideChunkList(ChunkList const & chunkList, Vector const & start_o, Vector const & end_o, CollisionInfo & result) const; + +protected: + + SamplerProceduralTerrainAppearanceTemplate &terrainSamplerTemplate; + + ChunkMap* const m_chunkMap; + +private: + + class CollisionChunkSorter; + +private: + + SamplerProceduralTerrainAppearance (); + SamplerProceduralTerrainAppearance (const SamplerProceduralTerrainAppearance&); + SamplerProceduralTerrainAppearance& operator= (const SamplerProceduralTerrainAppearance&); + +private: + + int m_chunkMapKeyOffset; + + SamplerChunkList* const m_highUsedChunkList; + SamplerChunkList* const m_lowUsedChunkList; + SamplerChunkList* const m_unusedChunkList; + ChunkList* const m_invalidateChunkList; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.cpp new file mode 100644 index 00000000..ef9d9b1b --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearanceTemplate.cpp @@ -0,0 +1,501 @@ +//=================================================================== +// +// SamplerProceduralTerrainAppearanceTemplate.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/SamplerProceduralTerrainAppearanceTemplate.h" +#include "sharedTerrain/SamplerProceduralTerrainAppearance.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedUtility/PackedIntegerMap.h" +#include "sharedUtility/PackedFixedPointMap.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "fileInterface/StdioFile.h" +#include "sharedFile/TreeFile.h" + +#include +#if defined(PLATFORM_LINUX) +#include +#endif + +//=================================================================== + +struct StaticFloraSampleFileHeader +{ + char terrainName[64]; + float floraTileWidthInMeters; + int numberOfFloraSampled; +}; + +struct StaticFloraSampleHeightPlaneHeader +{ + int version; + float minHeight; + float maxHeight; + float scale; + int nibblesPerEntry; +}; + +struct CollidableFloraSampleFileHeader +{ + uint32 type; + int version; + char terrainName[64]; + float floraTileWidthInMeters; + int minFloraTileX; + int minFloraTileZ; + int maxFloraTileX; + int maxFloraTileZ; + int numberOfFloraSampled; + float minHeight; + float maxHeight; +}; + +//=================================================================== + +AppearanceTemplate* SamplerProceduralTerrainAppearanceTemplate::create (const char* filename, Iff* iff) +{ + return new SamplerProceduralTerrainAppearanceTemplate (filename, iff); +} + +//=================================================================== + +SamplerProceduralTerrainAppearanceTemplate::SamplerProceduralTerrainAppearanceTemplate (const char* filename, Iff* iff) : + ProceduralTerrainAppearanceTemplate (filename, iff, false, 0, 1, true), + m_staticCollidableFloraHeightMin(0), + m_staticCollidableFloraHeightMax(0), + m_staticCollidableFloraHeightSamples(0), + m_staticCollidableFloraSamples(0), + m_numberOfSampledFlora(0) +{ + if (m_legacyMap) + { + _setSamplingParameters(true, 3, 3); + } +} + +//------------------------------------------------------------------- + +SamplerProceduralTerrainAppearanceTemplate::~SamplerProceduralTerrainAppearanceTemplate () +{ + delete [] m_staticCollidableFloraHeightSamples; + m_staticCollidableFloraHeightSamples=0; + + delete [] m_staticCollidableFloraSamples; + m_staticCollidableFloraSamples=0; +} + +//------------------------------------------------------------------- + +Appearance* SamplerProceduralTerrainAppearanceTemplate::createAppearance () const +{ + return new SamplerProceduralTerrainAppearance (const_cast(this)); +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearanceTemplate::setMapsToSample(unsigned maps) +{ + m_terrainGenerator->setMapsToSample(maps); +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearanceTemplate::getFloraHeightSample(int key, float &o_height) const +{ + if (!m_staticCollidableFloraHeightSamples) + { + o_height=0; + return false; + } + else + { + o_height = m_staticCollidableFloraHeightSamples[key]; + return true; + } +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearanceTemplate::beginStaticCollidableFloraSampling() +{ + m_staticCollidableFloraHeightMin = FLT_MAX; + m_staticCollidableFloraHeightMax = -FLT_MAX; + + const int numElements = sqr(getMapWidthInFlora()); + + float *staticCollidableFloraHeightSamples = new float[numElements]; + memset(staticCollidableFloraHeightSamples, 0, numElements*sizeof(*staticCollidableFloraHeightSamples)); + m_staticCollidableFloraHeightSamples=staticCollidableFloraHeightSamples; + + FloraGroup::Info *staticCollidableFloraSamples = new FloraGroup::Info[numElements]; + memset(staticCollidableFloraSamples, 0, numElements*sizeof(*staticCollidableFloraSamples)); + m_staticCollidableFloraSamples = staticCollidableFloraSamples; + + m_numberOfSampledFlora=0; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearanceTemplate::loadStaticCollidableFloraFile(const char *i_filename) +{ + if (!m_staticCollidableFloraHeightSamples) + { + beginStaticCollidableFloraSampling(); + } + + // ------------------------------------------------------- + + AbstractFile *mapFile = TreeFile::open(i_filename, AbstractFile::PriorityData, true); + if (!mapFile) + { + REPORT_LOG_PRINT(true, ("Could not open sample file %s\n", i_filename)); + return false; + } + + // ------------------------------------------------------- + + CollidableFloraSampleFileHeader fileHeader; + mapFile->read(&fileHeader, sizeof(fileHeader)); + + if (fileHeader.type!=TGM_floraStaticCollidable) + { + return false; + } + + if (fileHeader.version!=1) + { + return false; + } + + if (fileHeader.floraTileWidthInMeters!=getFloraTileWidthInMeters()) + { + return false; + } + + // ------------------------------------------------------- + + int xWidth = fileHeader.maxFloraTileX - fileHeader.minFloraTileX; + int z; + for (z=fileHeader.minFloraTileZ;zread(row+fileHeader.minFloraTileX, xWidth*sizeof(*row)); + } + + for (z=fileHeader.minFloraTileZ;zread(row+fileHeader.minFloraTileX, xWidth*sizeof(*row)); + } + + // ------------------------------------------------------- + + + delete mapFile; + + return true; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearanceTemplate::setFloraTileSample(int key, const FloraGroup::Info &i_data, float height) +{ + FloraGroup::Info &info = m_staticCollidableFloraSamples[key]; + if (!info.getFamilyId()) + { + info=i_data; + if (i_data.getFamilyId()) + { + if (height>m_staticCollidableFloraHeightMax) + { + m_staticCollidableFloraHeightMax=height; + } + if (heighti_filename) + { + if ( iter[-1]=='/' + || iter[-1]=='\\' + || iter[-1]==':' + ) + { + break; + } + iter--; + } + + // iter should now point to beginning of planet name + char *oiter=o_buffer; + while (*iter && *iter!='.') + { + *oiter++=*iter++; + } + *oiter++=0; + + return true; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearanceTemplate::writeStaticCollidableFloraFile(const char *i_filename, int tileBounds[4]) const +{ + if (!m_samplingMode) + { + return false; + } + AbstractFile *of = StdioFileFactory().createFile(i_filename, "wb"); + if (!of) + { + return false; + } + + char planetname[256]; + strcpy(planetname, "terrain\\"); + if (!_extractPlanetName(strrchr(planetname, 0), i_filename)) + { + return false; + } + strcat(planetname, ".trn"); + + // -------------------------------------------- + + CollidableFloraSampleFileHeader fileHeader; + Zero(fileHeader); + + fileHeader.type=TGM_floraStaticCollidable; + fileHeader.version=1; + strcpy(fileHeader.terrainName, planetname); + fileHeader.floraTileWidthInMeters = getFloraTileWidthInMeters(); + fileHeader.minFloraTileX = tileBounds[0]; + fileHeader.minFloraTileZ = tileBounds[1]; + fileHeader.maxFloraTileX = tileBounds[2]; + fileHeader.maxFloraTileZ = tileBounds[3]; + fileHeader.numberOfFloraSampled=0; + fileHeader.minHeight = FLT_MAX; + fileHeader.maxHeight = -FLT_MAX; + + // -------------------------------------------- + + int x, z; + for (z=tileBounds[1];zfileHeader.maxHeight) + { + fileHeader.maxHeight=heightRow[x]; + } + } + + const FloraGroup::Info *infoRow = m_staticCollidableFloraSamples + z*getMapWidthInFlora(); + for (x=tileBounds[0];xwrite(sizeof(fileHeader), &fileHeader); + + int xWidth = tileBounds[2] - tileBounds[0]; + for (z=tileBounds[1];zwrite(xWidth*sizeof(*row), row+tileBounds[0]); + } + + for (z=tileBounds[1];zwrite(xWidth*sizeof(*row), row+tileBounds[0]); + } + + of->close(); + + delete of; + + // -------------------------------------------------------- + + + return true; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearanceTemplate::writeOldStaticCollidableFloraFile(const char *i_filename) const +{ + if (!m_samplingMode) + { + return false; + } + AbstractFile *of = StdioFileFactory().createFile(i_filename, "wb"); + if (!of) + { + return false; + } + + char planetname[256]; + strcpy(planetname, "terrain\\"); + if (!_extractPlanetName(strrchr(planetname, 0), i_filename)) + { + return false; + } + strcat(planetname, ".trn"); + + StaticFloraSampleFileHeader fileHeader; + Zero(fileHeader); + + strcpy(fileHeader.terrainName, planetname); + fileHeader.floraTileWidthInMeters = getFloraTileWidthInMeters(); + fileHeader.numberOfFloraSampled=m_numberOfSampledFlora; + + of->write(sizeof(fileHeader), &fileHeader); + of->write(sqr(getMapWidthInFlora())*sizeof(*m_staticCollidableFloraSamples), m_staticCollidableFloraSamples); + of->close(); + delete of; + + // -------------------------------------------------------- + + char buffer[1024]; + strcpy(buffer, i_filename); + strcat(buffer, "2"); + writeOldStaticCollidableFloraHeightFile(buffer); + + // -------------------------------------------------------- + + return true; +} + +//------------------------------------------------------------------- + +bool SamplerProceduralTerrainAppearanceTemplate::writeOldStaticCollidableFloraHeightFile(const char *i_filename) const +{ + if (!m_samplingMode) + { + return false; + } + AbstractFile *of = StdioFileFactory().createFile(i_filename, "wb"); + if (!of) + { + return false; + } + + char planetname[256]; + strcpy(planetname, "terrain\\"); + if (!_extractPlanetName(strrchr(planetname, 0), i_filename)) + { + return false; + } + strcat(planetname, ".trn"); + + StaticFloraSampleHeightPlaneHeader fileHeader; + Zero(fileHeader); + + //strcpy(fileHeader.terrainName, planetname); + + fileHeader.version = 1; + fileHeader.minHeight = m_staticCollidableFloraHeightMin; + fileHeader.maxHeight = m_staticCollidableFloraHeightMax; + fileHeader.scale = 1.0f / 50.0f; + fileHeader.nibblesPerEntry = 8; + + of->write(sizeof(fileHeader), &fileHeader); + size_t heightSize = sqr(getMapWidthInFlora()); + of->write(heightSize*sizeof(*m_staticCollidableFloraHeightSamples), m_staticCollidableFloraHeightSamples); + of->close(); + delete of; + + return true; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearanceTemplate::commitStaticCollidableFloraSamples(int *tileBounds) +{ + const int mapWidthInFlora = getMapWidthInFlora(); + + if (tileBounds) + { + int x, z; + + // initialize everything outside the bounds with the original data. + + const int xstart = (tileBounds) ? clamp(0, tileBounds[0], mapWidthInFlora) : 0; + const int zstart = (tileBounds) ? clamp(0, tileBounds[1], mapWidthInFlora) : 0; + const int xstop = (tileBounds) ? clamp(0, tileBounds[2], mapWidthInFlora) : mapWidthInFlora; + const int zstop = (tileBounds) ? clamp(0, tileBounds[3], mapWidthInFlora) : mapWidthInFlora; + + for (z=0;z=zstart && z +#include + +//================================================================== + +namespace SamplerProceduralTerrainAppearanceCacheNamespace +{ + typedef std::vector*> VertexListList; + typedef std::vector*> PlaneListList; + typedef std::vector*> ShaderGroupList; + typedef std::vector*> FloraGroupList; + typedef std::vector*> PassableMapList; + + bool ms_installed; + uint ms_preloadSize = 2048; + VertexListList* ms_vertexListList; + PlaneListList* ms_planeListList; + ShaderGroupList* ms_shaderMapList; + FloraGroupList* ms_floraMapList; + PassableMapList* ms_passableMapList; + +#ifdef _DEBUG + bool ms_debugReport; +#endif + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void debugDump (); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + ArrayList* localCreateVertexList (const int size) + { + ArrayList* const vertexList = new ArrayList; + vertexList->preallocate (size, true); + + return vertexList; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + ArrayList* localCreatePlaneList (const int size) + { + ArrayList* const planeList = new ArrayList; + planeList->preallocate (size, true); + + return planeList; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Array2d* localCreateShaderMap (const int width, const int height) + { + Array2d* const map = new Array2d; + map->allocate (width, height); + + return map; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Array2d* localCreateFloraMap (const int width, const int height) + { + Array2d* const map = new Array2d; + map->allocate (width, height); + + return map; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Array2d* localCreatePassableMap (const int width, const int height) + { + Array2d* const map = new Array2d; + map->allocate (width, height); + + return map; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace SamplerProceduralTerrainAppearanceCacheNamespace; + +//================================================================== + +void SamplerProceduralTerrainAppearance::Cache::install () +{ + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportInstall (), ("SamplerProceduralTerrainAppearance::Cache::install\n")); + + DEBUG_FATAL (ms_installed, ("already installed")); + ms_installed = true; + + ms_preloadSize = static_cast (ConfigSharedTerrain::getMaximumNumberOfChunksAllowed ()); + + //-- can't precreate maps because we don't know what size they will be + ms_vertexListList = new VertexListList; + ms_planeListList = new PlaneListList; + ms_shaderMapList = new ShaderGroupList; + ms_floraMapList = new FloraGroupList; + ms_passableMapList = new PassableMapList; + +#ifdef _DEBUG + DebugFlags::registerFlag (SamplerProceduralTerrainAppearanceCacheNamespace::ms_debugReport, "SharedTerrain", "reportSamplerProceduralTerrainAppearanceCache", SamplerProceduralTerrainAppearanceCacheNamespace::debugDump); +#endif +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::remove () +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + ms_installed = false; + + //-- delete non-array lists +#define DELETE_SPECIFIC_LIST(a) { \ + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportLogPrint (), ("Terrain Cache %sList = %i\n", #a, ms_ ## a ## List->size ())); \ + std::for_each (ms_ ## a ## List->begin (), ms_ ## a ## List->end (), PointerDeleter ()); \ + delete ms_ ## a ## List; \ + ms_ ## a ## List = 0; \ + } + + DELETE_SPECIFIC_LIST (vertexList); + DELETE_SPECIFIC_LIST (planeList); + DELETE_SPECIFIC_LIST (shaderMap); + DELETE_SPECIFIC_LIST (floraMap); + DELETE_SPECIFIC_LIST (passableMap); + +#ifdef _DEBUG + DebugFlags::unregisterFlag (SamplerProceduralTerrainAppearanceCacheNamespace::ms_debugReport); +#endif +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::warm (const int vertexListSize, const int planeListSize, const int mapSize) +{ + NOT_NULL (ms_vertexListList); + ms_vertexListList->reserve (ms_preloadSize); + + NOT_NULL (ms_planeListList); + ms_planeListList->reserve (ms_preloadSize); + + NOT_NULL (ms_shaderMapList); + ms_shaderMapList->reserve (ms_preloadSize); + + NOT_NULL (ms_floraMapList); + ms_floraMapList->reserve (ms_preloadSize); + + NOT_NULL (ms_passableMapList); + ms_passableMapList->reserve (ms_preloadSize); + + uint i; + for (i = 0; i < ms_preloadSize; ++i) + { + ms_vertexListList->push_back (localCreateVertexList (vertexListSize)); + ms_planeListList->push_back (localCreatePlaneList (planeListSize)); + ms_shaderMapList->push_back (localCreateShaderMap (mapSize, mapSize)); + ms_floraMapList->push_back (localCreateFloraMap (mapSize, mapSize)); + ms_passableMapList->push_back (localCreatePassableMap (mapSize, mapSize)); + } +} + +//------------------------------------------------------------------- + +ArrayList* SamplerProceduralTerrainAppearance::Cache::createVertexList (const int size) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_vertexListList); + + ArrayList* vertexList = 0; + + //-- just take one off the list + if (!ms_vertexListList->empty ()) + { + vertexList = ms_vertexListList->back (); + ms_vertexListList->pop_back (); + } + else + { + //-- create one + vertexList = localCreateVertexList (size); + } + + NOT_NULL (vertexList); + + return vertexList; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::destroyVertexList (ArrayList* const vertexList) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_vertexListList); + + if (vertexList) + ms_vertexListList->push_back (vertexList); +} + +//------------------------------------------------------------------- + +ArrayList* SamplerProceduralTerrainAppearance::Cache::createPlaneList (const int size) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_planeListList); + + ArrayList* planeList = 0; + + //-- just take one off the list + if (!ms_planeListList->empty ()) + { + planeList = ms_planeListList->back (); + ms_planeListList->pop_back (); + } + else + { + //-- create one + planeList = localCreatePlaneList (size); + } + + NOT_NULL (planeList); + + return planeList; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::destroyPlaneList (ArrayList* const planeList) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_planeListList); + + if (planeList) + ms_planeListList->push_back (planeList); +} + +//------------------------------------------------------------------- + +Array2d* SamplerProceduralTerrainAppearance::Cache::createShaderMap (int width, int height) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_shaderMapList); + + Array2d* map = 0; + + //-- just take one off the list + if (!ms_shaderMapList->empty ()) + { + map = ms_shaderMapList->back (); + ms_shaderMapList->pop_back (); + } + else + { + //-- create one + map = localCreateShaderMap (width, height); + } + + NOT_NULL (map); + DEBUG_FATAL (width != map->getWidth () && height != map->getHeight (), ("SamplerProceduralTerrainAppearance::Cache - cached map of wrong size")); + + return map; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::destroyShaderMap (Array2d* map) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_shaderMapList); + + if (map) + ms_shaderMapList->push_back (map); +} + +//------------------------------------------------------------------- + +Array2d* SamplerProceduralTerrainAppearance::Cache::createFloraMap (int width, int height) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_floraMapList); + + Array2d* map = 0; + + //-- just take one off the list + if (!ms_floraMapList->empty ()) + { + map = ms_floraMapList->back (); + ms_floraMapList->pop_back (); + } + else + { + //-- create one + map = localCreateFloraMap (width, height); + } + + NOT_NULL (map); + DEBUG_FATAL (width != map->getWidth () && height != map->getHeight (), ("SamplerProceduralTerrainAppearance::Cache - cached map of wrong size")); + + return map; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::destroyFloraMap (Array2d* map) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_floraMapList); + + if (map) + ms_floraMapList->push_back (map); +} + +//---------------------------------------------------------------------- + +Array2d* SamplerProceduralTerrainAppearance::Cache::createPassableMap (int width, int height) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_passableMapList); + + Array2d* map = 0; + + //-- just take one off the list + if (!ms_passableMapList->empty ()) + { + map = ms_passableMapList->back (); + ms_passableMapList->pop_back (); + } + else + { + //-- create one + map = localCreatePassableMap (width, height); + } + + NOT_NULL (map); + DEBUG_FATAL (width != map->getWidth () && height != map->getHeight (), ("SamplerProceduralTerrainAppearance::Cache - cached map of wrong size")); + + return map; +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearance::Cache::destroyPassableMap (Array2d* map) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_passableMapList); + + if (map) + ms_passableMapList->push_back (map); +} + +//------------------------------------------------------------------- + +void SamplerProceduralTerrainAppearanceCacheNamespace::debugDump () +{ +#ifdef _DEBUG + + DEBUG_FATAL (!ms_installed, ("not installed")); + + NOT_NULL (ms_vertexListList); + NOT_NULL (ms_planeListList); + NOT_NULL (ms_shaderMapList); + NOT_NULL (ms_floraMapList); + NOT_NULL (ms_passableMapList); + + DEBUG_REPORT_PRINT (ms_debugReport, ("vertexListList size = %i\n", ms_vertexListList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("planeListList size = %i\n", ms_planeListList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("shaderMapList size = %i\n", ms_shaderMapList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("floraMapList size = %i\n", ms_floraMapList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("passableMapList size = %i\n", ms_passableMapList->size ())); + +#endif +} + +//================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.h b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.h new file mode 100644 index 00000000..42bea42e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SamplerProceduralTerrainAppearance_Cache.h @@ -0,0 +1,53 @@ +//================================================================== +// +// SamplerProceduralTerrainAppearance_Cache.h +// asommers +// +// copyright 2002, sony online entertainment +// +//================================================================== + +#ifndef INCLUDED_SamplerProceduralTerrainAppearance_Cache_H +#define INCLUDED_SamplerProceduralTerrainAppearance_Cache_H + +//================================================================== + +#include "SamplerProceduralTerrainAppearance.h" + +//================================================================== + +class SamplerProceduralTerrainAppearance::Cache +{ +public: + + static void install (); + static void remove (); + + static void warm (int vertexListSize, int planeListSize, int mapSize); + + static ArrayList* createVertexList (int size); + static void destroyVertexList (ArrayList* vertexList); + + static ArrayList* createPlaneList (int size); + static void destroyPlaneList (ArrayList* planeList); + + static Array2d* createShaderMap (int width, int height); + static void destroyShaderMap (Array2d* map); + + static Array2d* createFloraMap (int width, int height); + static void destroyFloraMap (Array2d* map); + + static Array2d* createPassableMap (int width, int height); + static void destroyPassableMap (Array2d* map); + +private: + + Cache (); + ~Cache (); + Cache (const Cache&); + Cache& operator= (const Cache&); +}; + +//================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.cpp new file mode 100644 index 00000000..26d3c2ea --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.cpp @@ -0,0 +1,1257 @@ +//=================================================================== +// +// ServerProceduralTerrainAppearance.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerProceduralTerrainAppearance.h" + +#include "sharedCollision/BoxExtent.h" +#include "sharedCollision/CollideParameters.h" +#include "sharedCollision/CollisionInfo.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedDebug/Profiler.h" +#include "sharedMath/Plane.h" +#include "sharedMath/Line2d.h" +#include "sharedMath/Vector2d.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedObject/AlterResult.h" +#include "sharedObject/Object.h" +#include "sharedTerrain/ProceduralTerrainAppearanceTemplate.h" +#include "sharedTerrain/ServerProceduralTerrainAppearance_Cache.h" + +#include +#include +#include +#include +#include + +//=================================================================== + +namespace ServerProceduralTerrainAppearanceNamespace +{ + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + struct TriangleIndirectionData + { + int offsetX0; + int offsetZ0; + int offsetX1; + int offsetZ1; + int offsetX2; + int offsetZ2; + }; + + static const int TRIANGLE_INDIRECTION_ARRAY_SIZE = 8; + + static const TriangleIndirectionData constructionTriangleIndirectionArray [TRIANGLE_INDIRECTION_ARRAY_SIZE] = + { + // x1, z1, x2, z2, x3, z3 + { 1, 1, 0, 2, 1, 2 }, + { 1, 1, 1, 2, 2, 2 }, + { 1, 1, 2, 2, 2, 1 }, + { 1, 1, 2, 1, 2, 0 }, + { 1, 1, 2, 0, 1, 0 }, + { 1, 1, 1, 0, 0, 0 }, + { 1, 1, 0, 0, 0, 1 }, + { 1, 1, 0, 1, 0, 2 } + }; + + static int chunkIndirectionArray [16] = + { + -1, 1, + 0, 1, + 1, 1, + -1, 0, + 1, 0, + -1, -1, + 0, -1, + 1, -1 + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class DenormalizedLine2d + { + public: + + DenormalizedLine2d (const Vector2d& point0, const Vector2d& point1) : + m_normal (-point1.y + point0.y, point1.x - point0.x), + m_c (-m_normal.dot (point0)) + { + } + + float computeDistanceTo (const Vector2d& point) const + { + return m_normal.dot (point) + m_c; + } + + private: + + DenormalizedLine2d (); + + private: + + Vector2d m_normal; + float m_c; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace ServerProceduralTerrainAppearanceNamespace; + +// ---------------------------------------------------------------------- + +class ServerProceduralTerrainAppearance::CollisionChunkSorter +{ +public: + + explicit CollisionChunkSorter(Vector const & position_o); + ~CollisionChunkSorter(); + CollisionChunkSorter(CollisionChunkSorter const &); + CollisionChunkSorter & operator=(CollisionChunkSorter const &); + + bool operator()(Chunk const * Chunk1, Chunk const * Chunk2) const; + +private: + + CollisionChunkSorter(); + +private: + + Vector m_position_o; +}; + +// ---------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::CollisionChunkSorter::CollisionChunkSorter(Vector const & position_o) : + m_position_o(position_o) +{ +} + +// ---------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::CollisionChunkSorter::~CollisionChunkSorter() +{ +} + +// ---------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::CollisionChunkSorter::CollisionChunkSorter(CollisionChunkSorter const & rhs) : + m_position_o(rhs.m_position_o) +{ +} + +// ---------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::CollisionChunkSorter & ServerProceduralTerrainAppearance::CollisionChunkSorter::operator=(CollisionChunkSorter const & rhs) +{ + if (this != &rhs) + m_position_o = rhs.m_position_o; + + return *this; +} + +// ---------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::CollisionChunkSorter::operator()(Chunk const * const chunk1, Chunk const * const chunk2) const +{ + float const distanceSquaredToChunk1 = chunk1 ? m_position_o.magnitudeBetweenSquared(chunk1->getExtent()->getCenter()) : 0.f; + float const distanceSquaredToChunk2 = chunk2 ? m_position_o.magnitudeBetweenSquared(chunk2->getExtent()->getCenter()) : 0.f; + + return distanceSquaredToChunk1 < distanceSquaredToChunk2; +} + +//=================================================================== +// PUBLIC STATIC ServerProceduralTerrainAppearance::ServerChunk +//=================================================================== + +ArrayList* ServerProceduralTerrainAppearance::ServerChunk::ms_indexList; + +//------------------------------------------------------------------- + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITHOUT_INSTALL (ServerProceduralTerrainAppearance::ServerChunk, false, 256, 4, 0); + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::ServerChunk::install () +{ + installMemoryBlockManager (); +} + +//---------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::ServerChunk::compareTimestampsGreater(ServerChunk const * const lhs, ServerChunk const * const rhs) +{ + return lhs->m_timeStamp > rhs->m_timeStamp; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::ServerChunk::createIndexList (const int numberOfTilesPerChunk, const int actualNumberOfPoles) +{ + const int size = sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE * 3; + ms_indexList = new ArrayList (size); + ms_indexList->preallocate (size, true); + + int indexIndex = 0; + + int x; + int z; + for (z = 0; z < numberOfTilesPerChunk; z++) + { + for (x = 0; x < numberOfTilesPerChunk; x++) + { + const int tileOriginX = x * 2; + const int tileOriginZ = z * 2; + + int i; + for (i = 0; i < TRIANGLE_INDIRECTION_ARRAY_SIZE; i++) + { + const int i0x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX0; + const int i0z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ0; + const int i0 = i0x + i0z * (actualNumberOfPoles); + + const int i1x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX1; + const int i1z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ1; + const int i1 = i1x + i1z * (actualNumberOfPoles); + + const int i2x = tileOriginX + constructionTriangleIndirectionArray [i].offsetX2; + const int i2z = tileOriginZ + constructionTriangleIndirectionArray [i].offsetZ2; + const int i2 = i2x + i2z * (actualNumberOfPoles); + + (*ms_indexList) [indexIndex++] = i0; + (*ms_indexList) [indexIndex++] = i1; + (*ms_indexList) [indexIndex++] = i2; + } + } + } +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::ServerChunk::remove () +{ + removeMemoryBlockManager (); + + delete ms_indexList; + ms_indexList = 0; +} + +//=================================================================== +// PUBLIC ServerProceduralTerrainAppearance::ServerChunk +//=================================================================== + +ServerProceduralTerrainAppearance::ServerChunk::ServerChunk (ProceduralTerrainAppearance& proceduralTerrainAppearance) : + Chunk (proceduralTerrainAppearance), + m_vertexList (0), + m_planeList (0), + m_timeStamp(time(0)) +{ +} + +//------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::ServerChunk::~ServerChunk () +{ + ServerProceduralTerrainAppearance::Cache::destroyVertexList (m_vertexList); + m_vertexList = 0; + + ServerProceduralTerrainAppearance::Cache::destroyPlaneList (m_planeList); + m_planeList = 0; + + ServerProceduralTerrainAppearance::Cache::destroyShaderMap (shaderMap); + shaderMap = 0; + + if (m_floraStaticCollidableMap) + { + ServerProceduralTerrainAppearance::Cache::destroyFloraMap(m_floraStaticCollidableMap); + m_floraStaticCollidableMap = 0; + } +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::ServerChunk::getHeightAt (const Vector& pos, float* const height) const +{ + return getHeightAt (pos, height, 0); +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::ServerChunk::getHeightAt (const Vector& pos, float* const height, Vector* const normal) const +{ + const Vector vmin = m_boxExtent.getMin (); + const Vector vmax = m_boxExtent.getMax (); + if (pos.x < vmin.x || pos.x > vmax.x || pos.z < vmin.z || pos.z > vmax.z) + { + DEBUG_WARNING (true, ("called getHeightAt for position not within chunk")); + return false; + } + + int tileX; + int tileZ; + _findTileXz(pos, tileX, tileZ); + if (isExcluded(tileX, tileZ)) + return false; + + //-- find out which tile this intersects + const Vector start (pos.x, vmax.y + 0.1f, pos.z); + const Vector end (pos.x, vmin.y - 0.1f, pos.z); + const Vector dir = end - start; + + //-- collide with the 8 polygons in the tile + bool found = false; + + CollisionInfo result; + result.setPoint (end); + + Vector intersection; + + int const numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + int const tileIndex = tileZ * numberOfTilesPerChunk + tileX; + const int offset = tileIndex * 8; + + int k; + for (k = offset; k < offset + 8; ++k) + { + const Plane& plane = (*m_planeList) [k]; + const Vector& normal = plane.getNormal (); + + if ((dir.dot (normal) < 0.f) && (plane.findIntersection (start, end, intersection))) + { + const int i0 = (*ms_indexList) [k * 3 + 0]; + const int i1 = (*ms_indexList) [k * 3 + 1]; + const int i2 = (*ms_indexList) [k * 3 + 2]; + + const Vector& v0 = (*m_vertexList) [i0]; + const Vector& v1 = (*m_vertexList) [i1]; + const Vector& v2 = (*m_vertexList) [i2]; + + DenormalizedLine2d const line01 (Vector2d (v0.x, v0.z), Vector2d (v1.x, v1.z)); + DenormalizedLine2d const line12 (Vector2d (v1.x, v1.z), Vector2d (v2.x, v2.z)); + DenormalizedLine2d const line20 (Vector2d (v2.x, v2.z), Vector2d (v0.x, v0.z)); + + if (line01.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line12.computeDistanceTo (Vector2d (start.x, start.z)) <= 0 && + line20.computeDistanceTo (Vector2d (start.x, start.z)) <= 0) + { + found = true; + + result.setPoint (intersection); + result.setNormal (normal); + } + } + } + + if (found) + { + if (height) + *height = result.getPoint ().y; + + if (normal) + *normal = result.getNormal (); + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +#define ALLOW_BACKFACING_COLLISION 0 + +bool ServerProceduralTerrainAppearance::ServerChunk::collide (const Vector& start, const Vector& end, CollideParameters const & /*collideParameters*/, CollisionInfo& result) const +{ + bool found = false; + + //-- test the line against the extent + if (m_boxExtent.testSphereOnly (start, end)) + { + NOT_NULL (m_vertexList); + NOT_NULL (m_planeList); + +#if ALLOW_BACKFACING_COLLISION == 0 + const Vector dir = end - start; +#endif + + Vector intersection; + + int const numberOfTilesPerChunk = m_proceduralTerrainAppearance.getNumberOfTilesPerChunk(); + for (int z = 0; z < numberOfTilesPerChunk; z++) + { + for (int x = 0; x < numberOfTilesPerChunk; x++) + { + if (isExcluded(x, z)) + continue; + + int const tileIndex = z * numberOfTilesPerChunk + x; + const int offset = tileIndex * 8; + + for (int k = offset; k < offset + 8; ++k) + { + const Plane& plane = (*m_planeList) [k]; + const Vector& normal = plane.getNormal (); + +#if ALLOW_BACKFACING_COLLISION == 0 + if ((dir.dot (normal) < 0.f) && (plane.findIntersection (start, end, intersection))) +#else + if (plane.findIntersection (start, end, intersection)) +#endif + { + const int i0 = (*ms_indexList) [k * 3 + 0]; + const int i1 = (*ms_indexList) [k * 3 + 1]; + const int i2 = (*ms_indexList) [k * 3 + 2]; + + const Vector& v0 = (*m_vertexList) [i0]; + const Vector& v1 = (*m_vertexList) [i1]; + const Vector& v2 = (*m_vertexList) [i2]; + + if ((start.magnitudeBetweenSquared (intersection) < start.magnitudeBetweenSquared (result.getPoint ())) && intersection.inPolygon (v0, v1, v2)) + { + found = true; + + result.setPoint (intersection); + result.setNormal (normal); + } + } + } + } + } + } + + return found; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::ServerChunk::create (const ProceduralTerrainAppearance::CreateChunkData& createChunkData) +{ + createChunkData.validate (); + + chunkX = createChunkData.chunkX; + chunkZ = createChunkData.chunkZ; + chunkWidthInMeters = createChunkData.chunkWidthInMeters; + originOffset = createChunkData.originOffset; + numberOfPoles = createChunkData.numberOfPoles; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- cache and verify all variables from createChunkData + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + const int numberOfTilesPerChunk = createChunkData.numberOfTilesPerChunk; + const int actualNumberOfPoles = (numberOfTilesPerChunk * 2) + 1; + + const Array2d* const ccd_shaderMap = &createChunkData.createChunkBuffer->shaderMap; + const Array2d* const ccd_floraStaticCollidableMap = &createChunkData.createChunkBuffer->floraStaticCollidableMap; + const Array2d* const ccd_excludeMap = &createChunkData.createChunkBuffer->excludeMap; + const Array2d* const ccd_passableMap = &createChunkData.createChunkBuffer->passableMap; + const Array2d* const vertexPositionMap = &createChunkData.createChunkBuffer->vertexPositionMap; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create the shared indexed triangle list if needed + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + if (!ms_indexList) + { + createIndexList (numberOfTilesPerChunk, actualNumberOfPoles); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- initialization + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_boxExtent.setMin(Vector::maxXYZ); + m_boxExtent.setMax(Vector::negativeMaxXYZ); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create and copy appropriate maps + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_vertexList = ServerProceduralTerrainAppearance::Cache::createVertexList (sqr (actualNumberOfPoles)); + m_planeList = ServerProceduralTerrainAppearance::Cache::createPlaneList (sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE); + + shaderMap = ServerProceduralTerrainAppearance::Cache::createShaderMap (numberOfPoles, numberOfPoles); + shaderMap->makeCopy (*ccd_shaderMap); + + if (getAppearanceTemplate()->getLegacyMode()) + { + m_floraStaticCollidableMap = ServerProceduralTerrainAppearance::Cache::createFloraMap (numberOfPoles, numberOfPoles); + m_floraStaticCollidableMap->makeCopy (*ccd_floraStaticCollidableMap); + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create vertex data + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + m_vertexList->clear (); + + for (int z = originOffset; z < originOffset + actualNumberOfPoles; z++) + { + for (int x = originOffset; x < originOffset + actualNumberOfPoles; x++) + { + m_vertexList->add(vertexPositionMap->getData(x,z)); + + m_boxExtent.updateMinAndMax(vertexPositionMap->getData(x,z)); + } + } + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- update extents + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + m_boxExtent.calculateCenterAndRadius(); + + Sphere boundingSphere = m_boxExtent.getSphere(); + boundingSphere.setRadius(boundingSphere.getRadius() + 0.001f); + m_boxExtent.setSphere(boundingSphere); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- create triangles and planes + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + //-- todo index list is the same for every chunk + m_planeList->preallocate (sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE, true); + + int indexIndex = 0; + int planeIndex = 0; + + int x; + int z; + for (z = 0; z < numberOfTilesPerChunk; z++) + { + for (x = 0; x < numberOfTilesPerChunk; x++) + { + const int tileOriginX = x * 2; + const int tileOriginZ = z * 2; + + if (!ccd_passableMap->getData (tileOriginX + originOffset, tileOriginZ + originOffset)) + { + setPassable(x, z, false); + } + + if (ccd_excludeMap->getData (tileOriginX + originOffset, tileOriginZ + originOffset)) + { + _setExcluded(x, z); + continue; + } + + int i; + for (i = 0; i < TRIANGLE_INDIRECTION_ARRAY_SIZE; i++) + { + const int i0 = (*ms_indexList) [indexIndex++]; + const int i1 = (*ms_indexList) [indexIndex++]; + const int i2 = (*ms_indexList) [indexIndex++]; + + (*m_planeList) [planeIndex++].set ((*m_vertexList) [i0], (*m_vertexList) [i1], (*m_vertexList) [i2]); + } + } + } + } +} + +//------------------------------------------------------------------- + +int ServerProceduralTerrainAppearance::ServerChunk::getChunkMemorySize () const +{ + const int geometrySize = sizeof (Vector) * m_vertexList->getNumberOfElements (); + const int planeSize = sizeof (Plane) * m_planeList->getNumberOfElements (); + +#ifdef _DEBUG + DEBUG_REPORT_PRINT (true, (" geometrySize = %i\n", geometrySize)); + DEBUG_REPORT_PRINT (true, (" planeSize = %i\n", planeSize)); +#endif + + return Chunk::getChunkMemorySize () + sizeof (*this) + geometrySize + planeSize; +} + +//=================================================================== +// PUBLIC ServerProceduralTerrainAppearance::ChunkSphereExtentAccessor +//=================================================================== + +Sphere const ServerProceduralTerrainAppearance::ChunkSphereExtentAccessor::getExtent (ServerProceduralTerrainAppearance::Chunk const * const chunk) +{ + return chunk->getBoxExtent ().getSphere (); +} + +//------------------------------------------------------------------- + +char const * ServerProceduralTerrainAppearance::ChunkSphereExtentAccessor::getDebugName (ServerProceduralTerrainAppearance::Chunk const * const /*chunk*/) +{ + return 0; +} + +//=================================================================== +// PUBLIC ServerProceduralTerrainAppearance +//=================================================================== + +ServerProceduralTerrainAppearance::ServerProceduralTerrainAppearance (const ProceduralTerrainAppearanceTemplate* appearanceTemplate) : + ProceduralTerrainAppearance (appearanceTemplate), + m_chunkMap (new ChunkMap), + m_chunkMapKeyOffset (0), + m_highUsedChunkList (new ServerChunkList), + m_lowUsedChunkList (new ServerChunkList), + m_unusedChunkList (new ServerChunkList), + m_invalidateChunkList (new ChunkList), + m_chunksCreatedThisFrame (new ChunkSet), + m_sphereTree () +{ + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- to ensure that memory isn't claimed on the client for server terrain (this must be first) + { + Cache::install (); + ServerChunk::install (); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + const_cast (appearanceTemplate->getTerrainGenerator ()->getShaderGroup ()).loadSurfaceProperties (); + + const float mapWidthInMeters = proceduralTerrainAppearanceTemplate->getMapWidthInMeters (); + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + const int numberOfTilesPerChunk = proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk (); + const int actualNumberOfPoles = (numberOfTilesPerChunk * 2) + 1; + DEBUG_FATAL(appearanceTemplate->getLegacyMode(), ("ServerProceduralTerrainAppearance should never run in legacy mode.\n")); + Cache::warm (sqr (actualNumberOfPoles), sqr (numberOfTilesPerChunk) * TRIANGLE_INDIRECTION_ARRAY_SIZE, numberOfPoles); + + m_chunkMapKeyOffset = static_cast (mapWidthInMeters / chunkWidthInMeters); +} + +//------------------------------------------------------------------- + +ServerProceduralTerrainAppearance::~ServerProceduralTerrainAppearance () +{ + while (!m_chunkMap->empty ()) + { + ChunkMap::iterator iter = m_chunkMap->begin (); + + delete iter->second; + m_chunkMap->erase (iter); + } + + delete m_chunkMap; + delete m_highUsedChunkList; + delete m_lowUsedChunkList; + delete m_unusedChunkList; + delete m_invalidateChunkList; + delete m_chunksCreatedThisFrame; + + DEBUG_WARNING (m_sphereTree.getObjectCount () != 0, ("ServerProceduralTerrainAppearance::m_sphereTree is not empty (%i)", m_sphereTree.getObjectCount ())); + + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- to ensure that memory isn't claimed on the client for server terrain (this must be last) + { + ServerChunk::remove (); + Cache::remove (); + } + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +//------------------------------------------------------------------- + +float ServerProceduralTerrainAppearance::alter (float time) +{ + PROFILER_AUTO_BLOCK_DEFINE("ServerProceduralTerrainAppearance::alter"); + m_chunksGeneratedThisFrame = 0; + m_chunksCreatedThisFrame->clear(); + + int i; + for (i = 0; i < getNumberOfReferenceObjects (); i++) + { + const Object* const object = getReferenceObject (i); + if (object->isInWorldCell ()) + ProceduralTerrainAppearance::createChunk (getOwner ()->rotateTranslate_w2o (object->getPosition_w ()), 1); + } + + IGNORE_RETURN (ProceduralTerrainAppearance::alter (time)); + + // @todo figure out what this should floatly return. + return AlterResult::cms_alterNextFrame; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::render () const +{ + DEBUG_FATAL (true, ("ServerProceduralTerrainAppearance::render should not be called")); +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::hasHighLevelOfDetailTerrain (const Vector& position_o) const +{ + return ProceduralTerrainAppearance::findChunk (position_o, 1) != 0; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::generateBetween(Vector const & start_o, Vector const & end_o, ChunkList & chunkList) +{ + int startX = calculateChunkX(start_o.x); + int startZ = calculateChunkZ(start_o.z); + int endX = calculateChunkX(end_o.x); + int endZ = calculateChunkZ(end_o.z); + + // if both sets of indices are invalid, we don't want to waste time trying to generate chunks + // if only one is invalid, we still want to check the valid chunks on the terrain from the valid point + if (!areValidChunkIndices(startX, startZ) && !areValidChunkIndices(endX, endZ)) + return; + + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + + typedef std::vector > GenerateList; + GenerateList generateList; + + if (startX == endX && startZ == endZ) + { + // if we are in the same chunk, just add it and be done with it + generateList.push_back(GenerateList::value_type(startX, startZ)); + } + else if (fabs(start_o.x - end_o.x) < 0.00001f && fabs(start_o.z - end_o.z) < 0.00001f) + { + // this is to not cause a debug_fatal on line2d construction + generateList.push_back(GenerateList::value_type(startX, startZ)); + generateList.push_back(GenerateList::value_type(endX, endZ)); + } + // we only want to do the complicated calculations on the shorter side + else if (abs(endX - startX) < abs(endZ - startZ)) + { + Line2d const line(start_o.x, start_o.z, end_o.x, end_o.z); + + // in order to make the boundary checks, we reorder the points so that startX <= endX + if (startX > endX) + { + std::swap(startX, endX); + std::swap(startZ, endZ); + } + + // this is the X value of the edge (parallel to the X axis) we will cross on our way to endX, this changes as we go through the loop + float boundingChunkEdgeX = (startX+1)*chunkWidthInMeters; + int subStartZ = startZ; + int subEndZ = endZ; + + for (int x = startX; x <= endX; ++x) + { + // if we are on the last X, we need to generate until endZ + if (x == endX) + subEndZ = endZ; + else + { + // we want to find out how far along on the X axis we need to generate chunks (subStartZ -> subEndZ) + // in these vectors, the y is our z here, since we are working in a 2d space + Vector2d intersect; + if (line.findIntersection(Vector2d(boundingChunkEdgeX, start_o.z), Vector2d(boundingChunkEdgeX, end_o.z), intersect)) + subEndZ = calculateChunkZ(intersect.y); + else + DEBUG_WARNING (true, ("ServerProceduralTerrainAppearance::did not intersect with boundingChunkX while generating chunks: startX %i, endX %i, startZ %i, endZ %i, boundingEdgeX %f", startX, endX, startZ, endZ, boundingChunkEdgeX)); + } + + // generate all chunks along the x axis that we need (inclusive of subStartZ and subEndZ) + int deltaZ = (subStartZ < subEndZ) ? 1 : -1; + for (int z = subStartZ; z != subEndZ; z += deltaZ) + generateList.push_back(GenerateList::value_type(x, z)); + generateList.push_back(GenerateList::value_type(x, subEndZ)); + + // along the next X axis (moves b/c of the for loop) we start at the endZ of this run + subStartZ = subEndZ; + + // move the boundingEdge to where it should be for the next loop + boundingChunkEdgeX += chunkWidthInMeters; + } + } + else + { + Line2d const line(start_o.x, start_o.z, end_o.x, end_o.z); + + // in order to make the boundary checks, we reorder the points so that startZ <= endZ + if (startZ > endZ) + { + std::swap(startX, endX); + std::swap(startZ, endZ); + } + + // this is the Z value of the edge (parallel to the Z axis) we will cross on our way to endZ, this changes as we go through the loop + float boundingChunkEdgeZ = (startZ+1)*chunkWidthInMeters; + int subStartX = startX; + int subEndX = endX; + + for (int z = startZ; z <= endZ; ++z) + { + // if we are on the last Z, we need to generate until endZ + if (z == endZ) + subEndX = endX; + else + { + // we want to find out how far along on the Z axis we need to generate chunks (subStartX -> subEndX) + Vector2d intersect; + if (line.findIntersection(Vector2d(start_o.x, boundingChunkEdgeZ), Vector2d(end_o.x, boundingChunkEdgeZ), intersect)) + subEndX = calculateChunkX(intersect.x); + else + DEBUG_WARNING (true, ("ServerProceduralTerrainAppearance::did not intersect with boundingChunkZ while generating chunks: startX %i, endX %i, startZ %i, endZ %i, boundingEdgeZ %f", startX, endX, startZ, endZ, boundingChunkEdgeZ)); + } + + // generate all chunks along this z axis that we need (inclusive of subStartX and subEndX) + int deltaX = (subStartX < subEndX) ? 1 : -1; + for (int x = subStartX; x != subEndX; x += deltaX) + generateList.push_back(GenerateList::value_type(x, z)); + generateList.push_back(GenerateList::value_type(subEndX, z)); + + // along the next Z axis (moves b/c of the for loop) we start at the endX of this run + subStartX = subEndX; + + // move the boundingEdge to where it should be for the next loop + boundingChunkEdgeZ += chunkWidthInMeters; + } + } + + // add on all chunks to be generated to chunkList. if we encounter invalid chunks (null), don't include them + const Chunk* chunk; + for (GenerateList::iterator iter = generateList.begin(); iter != generateList.end(); ++iter) + { + createChunk(iter->first, iter->second, 1, 0); + chunk = findChunk(iter->first, iter->second, 1); + + if (chunk) + chunkList.push_back(chunk); + } +} + +//=================================================================== +// PROTECTED ServerProceduralTerrainAppearance +//=================================================================== + +void ServerProceduralTerrainAppearance::createChunk (const int x, const int z, const int chunkSize, unsigned /*hasLargerNeighborFlags*/) +{ + //-- make sure indices are valid + if (!areValidChunkIndices (x, z)) + return; + + //-- see if the chunk already exists + if (findChunk (x, z, chunkSize) != 0) + return; + + const TerrainGenerator* terrainGenerator = proceduralTerrainAppearanceTemplate->getTerrainGenerator (); + const int numberOfTilesPerChunk = proceduralTerrainAppearanceTemplate->getNumberOfTilesPerChunk (); + const float chunkWidthInMeters = proceduralTerrainAppearanceTemplate->getChunkWidthInMeters (); + const float tileWidthInMeters = proceduralTerrainAppearanceTemplate->getTileWidthInMeters (); + + //-- chunk does not exist -- it needs to be created. find out what map data i'll need to ask the generator for + const float distanceBetweenPoles = tileWidthInMeters * 0.5f; + + const Vector start ( + static_cast(x)*chunkWidthInMeters - static_cast(originOffset)*distanceBetweenPoles, + 0.0f, + static_cast(z)*chunkWidthInMeters - static_cast(originOffset)*distanceBetweenPoles); + + ServerChunk* chunk = new ServerChunk (*this); + + //-- setup data needed to create a chunk + ProceduralTerrainAppearance::CreateChunkData createChunkData (&createChunkBuffer); + + createChunkData.chunkX = x; + createChunkData.chunkZ = z; + createChunkData.start = start; + createChunkData.numberOfTilesPerChunk = numberOfTilesPerChunk; + createChunkData.chunkWidthInMeters = chunkWidthInMeters; + createChunkData.tileWidthInMeters = tileWidthInMeters; + createChunkData.shaderGroup = &terrainGenerator->getShaderGroup (); + createChunkData.floraGroup = &terrainGenerator->getFloraGroup (); + createChunkData.radialGroup = &terrainGenerator->getRadialGroup (); + createChunkData.environmentGroup = &terrainGenerator->getEnvironmentGroup (); + createChunkData.fractalGroup = &terrainGenerator->getFractalGroup (); + createChunkData.bitmapGroup = &terrainGenerator->getBitmapGroup (); + createChunkData.originOffset = originOffset; + createChunkData.numberOfPoles = numberOfPoles; + + //-- ask the generator to fill out this area + TerrainGenerator::GeneratorChunkData generatorChunkData(proceduralTerrainAppearanceTemplate->getLegacyMode()); + + generatorChunkData.heightMap = &createChunkData.createChunkBuffer->heightMap; + generatorChunkData.colorMap = &createChunkData.createChunkBuffer->colorMap; + generatorChunkData.shaderMap = &createChunkData.createChunkBuffer->shaderMap; + generatorChunkData.floraStaticCollidableMap = &createChunkData.createChunkBuffer->floraStaticCollidableMap; + generatorChunkData.floraStaticNonCollidableMap = &createChunkData.createChunkBuffer->floraStaticNonCollidableMap; + generatorChunkData.floraDynamicNearMap = &createChunkData.createChunkBuffer->floraDynamicNearMap; + generatorChunkData.floraDynamicFarMap = &createChunkData.createChunkBuffer->floraDynamicFarMap; + generatorChunkData.environmentMap = &createChunkData.createChunkBuffer->environmentMap; + generatorChunkData.vertexPositionMap = &createChunkData.createChunkBuffer->vertexPositionMap; + generatorChunkData.vertexNormalMap = &createChunkData.createChunkBuffer->vertexNormalMap; + generatorChunkData.excludeMap = &createChunkData.createChunkBuffer->excludeMap; + generatorChunkData.passableMap = &createChunkData.createChunkBuffer->passableMap; + generatorChunkData.start = start; + generatorChunkData.originOffset = originOffset; + generatorChunkData.numberOfPoles = numberOfPoles; + generatorChunkData.upperPad = upperPad; + generatorChunkData.distanceBetweenPoles = distanceBetweenPoles; + generatorChunkData.shaderGroup = &terrainGenerator->getShaderGroup (); + generatorChunkData.floraGroup = &terrainGenerator->getFloraGroup (); + generatorChunkData.radialGroup = &terrainGenerator->getRadialGroup (); + generatorChunkData.environmentGroup = &terrainGenerator->getEnvironmentGroup (); + generatorChunkData.fractalGroup = &terrainGenerator->getFractalGroup (); + generatorChunkData.bitmapGroup = &terrainGenerator->getBitmapGroup (); + + terrainGenerator->generateChunk (generatorChunkData); + + //-- create the chunk using the data the generator created + chunk->create (createChunkData); + createFlora (chunk); + + addChunk (chunk, chunkSize); + +} //lint !e429 //-- chunk has not been freed or returned + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::ServerChunk::writeChunkData (const char* filename) const +{ + FILE* outfile = fopen (filename, "wt"); + if (!outfile) + return; + + NOT_NULL (m_vertexList); + + int i; + for (i = 0; i < m_vertexList->getNumberOfElements (); i++) + { + Vector v = (*m_vertexList) [i]; + + fprintf (outfile, "%4i <%5.1f, %5.1f, %5.1f>\n", i, v.x, v.y, v.z); + } + + fclose (outfile); +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::writeChunkData (int chunkX, int chunkZ) const +{ + //-- create chunk + const_cast (this)->createChunk (chunkX, chunkZ, 1, 0); + + //-- get chunk + const ServerChunk* chunk = dynamic_cast (findChunk (chunkX, chunkZ, 1)); + NOT_NULL (chunk); + + //-- write chunk + char filename [100]; + sprintf (filename, "%3i_%3i.txt", chunkX, chunkZ); + chunk->writeChunkData (filename); +} + +//------------------------------------------------------------------- + +int ServerProceduralTerrainAppearance::getTerrainType (const Vector& position_o) const +{ + Vector result = position_o; + float waterHeight; + if (getHeight (position_o, result.y) && getWaterHeight (position_o, waterHeight) && result.y < waterHeight) + return 1; + + return 0; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::invalidateRegion (const Rectangle2d& extent2d) +{ + m_invalidateChunkList->clear (); + + //-- figure out which chunks we need to invalidate + { + ChunkMap::iterator iter = m_chunkMap->begin (); + ChunkMap::iterator end = m_chunkMap->end (); + for (; iter != end; ++iter) + { + const Chunk* const chunk = iter->second; + const BoxExtent& boxExtent = chunk->getBoxExtent (); + const Rectangle2d chunkExtent2d (boxExtent.getMin ().x, boxExtent.getMin ().z, boxExtent.getMax ().x, boxExtent.getMax ().z); + if (extent2d.intersects (chunkExtent2d)) + m_invalidateChunkList->push_back (chunk); + } + } + + //-- delete those chunks + { + while (!m_invalidateChunkList->empty ()) + { + const Chunk* const chunk = m_invalidateChunkList->back (); + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + delete iter->second; + m_chunkMap->erase (iter); + m_chunksCreatedThisFrame->erase(iter->first); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + m_invalidateChunkList->pop_back (); + } + } +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::removeUnnecessaryChunk () +{ + //-- figure out which high chunks are in use + { + m_highUsedChunkList->clear (); + m_highUsedChunkList->reserve (static_cast (getNumberOfReferenceObjects ())); + + int i; + for (i = 0; i < getNumberOfReferenceObjects (); ++i) + { + const Object* const object = getReferenceObject (i); + if (object->isInWorld () && object->isInWorldCell ()) + { + const Vector& position = object->getPosition_w (); + const ServerChunk* const chunk = safe_cast(ProceduralTerrainAppearance::findChunk (position, 1)); + if (chunk) + m_highUsedChunkList->push_back (chunk); + } + } + + std::sort (m_highUsedChunkList->begin (), m_highUsedChunkList->end ()); + ServerChunkList::iterator iter = std::unique (m_highUsedChunkList->begin (), m_highUsedChunkList->end ()); + IGNORE_RETURN (m_highUsedChunkList->erase (iter, m_highUsedChunkList->end ())); + } + + //-- figure out which low chunks are in use + { + m_lowUsedChunkList->clear (); + m_lowUsedChunkList->reserve (m_highUsedChunkList->size () * 8); + + uint i; + for (i = 0; i < m_highUsedChunkList->size (); ++i) + { + const ServerChunk* const chunk = (*m_highUsedChunkList) [i]; + const int chunkX = chunk->getChunkX (); + const int chunkZ = chunk->getChunkZ (); + + int j; + for (j = 0; j < 8; ++j) + { + const ServerChunk* const lowChunk = safe_cast(findChunk (chunkX + chunkIndirectionArray [j * 2 + 0], chunkZ + chunkIndirectionArray [j * 2 + 1], 1)); + if (lowChunk && !std::binary_search (m_highUsedChunkList->begin (), m_highUsedChunkList->end (), lowChunk)) + m_lowUsedChunkList->push_back (lowChunk); + } + } + + std::sort (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end ()); + ServerChunkList::iterator iter = std::unique (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end ()); + IGNORE_RETURN (m_lowUsedChunkList->erase (iter, m_lowUsedChunkList->end ())); + } + + //-- iterate through the tree and delete chunks not in use + { + m_unusedChunkList->clear (); + m_unusedChunkList->reserve (static_cast (getNumberOfChunks ())); + + ChunkMap::iterator iter = m_chunkMap->begin (); + ChunkMap::iterator end = m_chunkMap->end (); + for (; iter != end; ++iter) + { + const ServerChunk* const chunk = safe_cast(iter->second); + + if (!std::binary_search (m_highUsedChunkList->begin (), m_highUsedChunkList->end (), chunk) && + !std::binary_search (m_lowUsedChunkList->begin (), m_lowUsedChunkList->end (), chunk) && + !m_chunksCreatedThisFrame->count(computeChunkMapKey(chunk->getChunkX(), chunk->getChunkZ()))) + m_unusedChunkList->push_back (chunk); + } + } + + //-- sort the unused chunks by timestamp so the oldest ones get deleted first + std::sort(m_unusedChunkList->begin(), m_unusedChunkList->end(), ServerChunk::compareTimestampsGreater); + + //-- can I delete at least 10 unused Chunks? + int chunksToDelete = 128; + while (chunksToDelete > 0 && !m_unusedChunkList->empty ()) + { + const Chunk* const chunk = m_unusedChunkList->back (); + NOT_NULL (chunk); + + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + DEBUG_FATAL (chunk != iter->second, ("chunk in unused chunklist does not match chunk found in chunkmap")); + + // we don't need to check if this is in the chunksCreatedThisFrame, + // the unusedChunkList was created w/ the condition that it's elements were not created this frame (see above) + delete iter->second; + m_chunkMap->erase (iter); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + m_unusedChunkList->pop_back (); + --chunksToDelete; + } + + if (chunksToDelete > 0) + { + //-- sort the low chunks by timestamp so the oldest ones get deleted first + std::sort(m_lowUsedChunkList->begin(), m_lowUsedChunkList->end(), ServerChunk::compareTimestampsGreater); + + while (chunksToDelete > 0 && !m_lowUsedChunkList->empty ()) + { + const Chunk* const chunk = m_lowUsedChunkList->back (); + NOT_NULL (chunk); + + // only delete this chunk if it was not created in this frame + if (!m_chunksCreatedThisFrame->count(computeChunkMapKey(chunk->getChunkX(), chunk->getChunkZ()))) + { + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ())); + ChunkMap::iterator end = m_chunkMap->end (); + if (iter != end) + { + DEBUG_FATAL (chunk != iter->second, ("chunk in unused chunklist does not match chunk found in chunkmap")); + + delete iter->second; + m_chunkMap->erase (iter); + } + else + DEBUG_WARNING (true, ("trying to delete non-existant chunk")); + + --chunksToDelete; + } + + m_lowUsedChunkList->pop_back (); + } + } +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::addChunk (Chunk* const chunk, const int /*chunkSize*/) +{ + const uint32 key = computeChunkMapKey (chunk->getChunkX (), chunk->getChunkZ ()); + + bool result = m_chunkMap->insert (std::make_pair (key, chunk)).second; + UNREF (result); + DEBUG_FATAL (!result, ("")); + result = m_chunksCreatedThisFrame->insert (key).second; + DEBUG_FATAL (!result, ("Failed to insert chunk into map for chunks created per frame")); + ++m_chunksGeneratedThisFrame; + + //-- add to sphere tree + chunk->setSpatialSubdivisionHandle (m_sphereTree.addObject (chunk)); +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::collideChunkList(ChunkList const & chunkList, Vector const & start_o, Vector const & end_o, CollisionInfo& result) const +{ + bool collided = false; + + result.setPoint (end_o); + + //-- fire ray through chunks + for (ChunkList::const_iterator iter = chunkList.begin (); iter != chunkList.end (); ++iter) + { + Chunk const * const chunk = *iter; + + CollisionInfo info; + if (chunk->collide (start_o, result.getPoint (), CollideParameters::cms_default, info)) + { + collided = true; + result = info; + } + } + + return collided; +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::collide(Vector const & start_o, Vector const & end_o, CollideParameters const & /*collideParameters*/, CollisionInfo & result) const +{ + ChunkList chunkList; + m_sphereTree.findOnSegment (start_o, end_o, chunkList); + std::stable_sort(chunkList.begin(), chunkList.end(), CollisionChunkSorter(start_o)); + + return collideChunkList(chunkList, start_o, end_o, result); +} + +//------------------------------------------------------------------- + +bool ServerProceduralTerrainAppearance::collideForceChunkCreation(Vector const & start_o, Vector const & end_o, CollisionInfo & result) +{ + ChunkList chunkList; + generateBetween(start_o, end_o, chunkList); + std::stable_sort(chunkList.begin(), chunkList.end(), CollisionChunkSorter(start_o)); + + return collideChunkList(chunkList, start_o, end_o, result); +} + +//------------------------------------------------------------------- + +int ServerProceduralTerrainAppearance::getNumberOfChunks () const +{ + return static_cast (m_chunkMap->size ()); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* ServerProceduralTerrainAppearance::findChunk (const int x, const int z, const int /*chunkSize*/) const +{ + ChunkMap::iterator iter = m_chunkMap->find (computeChunkMapKey (x, z)); + if (iter != m_chunkMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* ServerProceduralTerrainAppearance::findFirstRenderableChunk (const int x, const int z) const +{ + return findChunk (x, z, 1); +} + +//------------------------------------------------------------------- + +const ProceduralTerrainAppearance::Chunk* ServerProceduralTerrainAppearance::findAnyChunk () const +{ + if (m_chunkMap->empty ()) + return 0; + + return m_chunkMap->begin ()->second; +} + +//------------------------------------------------------------------- + +uint32 ServerProceduralTerrainAppearance::computeChunkMapKey (const int x, const int z) const +{ + return ((x + m_chunkMapKeyOffset) & 0x0FFFF) << 16 | ((z + m_chunkMapKeyOffset) & 0x0FFFF); +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::prepareForDelete (Chunk const * const chunk) +{ + m_sphereTree.removeObject (chunk->getSpatialSubdivisionHandle ()); + chunk->setSpatialSubdivisionHandle (0); + + ProceduralTerrainAppearance::prepareForDelete (chunk); +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::purgeChunks() +{ + while (!m_chunkMap->empty ()) + { + ChunkMap::iterator iter = m_chunkMap->begin (); + + delete iter->second; + m_chunkMap->erase (iter); + m_chunksCreatedThisFrame->erase(iter->first); + } +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.h new file mode 100644 index 00000000..1c6ea9a4 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance.h @@ -0,0 +1,161 @@ +//=================================================================== +// +// ServerProceduralTerrainAppearance.h +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_ServerProceduralTerrainAppearance_h +#define INCLUDED_ServerProceduralTerrainAppearance_h + +//=================================================================== + +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedMath/SphereTree.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" + +class Plane; +class MemoryBlockManager; + +//=================================================================== + +class ServerProceduralTerrainAppearance : public ProceduralTerrainAppearance +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Chunk defines a chunk of terrain in the terrain system + // + class ServerChunk : public ProceduralTerrainAppearance::Chunk + { + MEMORY_BLOCK_MANAGER_INTERFACE_WITHOUT_INSTALL; + + protected: + + // indexList is a list of triplets indexing the vertex positions used in each triangle of the chunk. + static ArrayList* ms_indexList; + + protected: + + // vertexList is a list of 3D positions for the chunk's height poles. size is (numberOfHeightPoles-2)^2 + ArrayList* m_vertexList; + + // planeList is a list of planes corresponding to the above triangles + ArrayList* m_planeList; + + time_t m_timeStamp; + + private: + + static void createIndexList (int numberOfTilesPerChunk, int actualNumberOfPoles); + + private: + + ServerChunk (); + ServerChunk (const ServerChunk& rhs); + ServerChunk& operator= (const ServerChunk& rhs); + + public: + + static void install (); + static void remove (); + static bool compareTimestampsGreater(ServerChunk const * lhs, ServerChunk const * rhs); + + public: + + explicit ServerChunk (ProceduralTerrainAppearance& proceduralTerrainAppearance); + virtual ~ServerChunk (); + + virtual bool getHeightAt (const Vector& worldPos, float* height) const; + virtual bool getHeightAt (const Vector& worldPos, float* height, Vector* normal) const; + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + virtual int getChunkMemorySize () const; + + void create (const ProceduralTerrainAppearance::CreateChunkData& newCreateChunkData); + + void writeChunkData (const char* filename) const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Cache; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +public: + + ServerProceduralTerrainAppearance (const ProceduralTerrainAppearanceTemplate* appearanceTemplate); + virtual ~ServerProceduralTerrainAppearance (); + + virtual float alter (float time); + virtual void render () const; + virtual void writeChunkData (int chunkX, int chunkZ) const; + virtual int getTerrainType (const Vector& position_o) const; + virtual void invalidateRegion (const Rectangle2d& extent2d); + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + virtual bool collideForceChunkCreation (Vector const & start_o, Vector const & end_o, CollisionInfo & result); + virtual int getNumberOfChunks () const; + virtual bool hasHighLevelOfDetailTerrain (const Vector& position_o) const; + virtual void purgeChunks(); + +protected: + + typedef stdmap::fwd ChunkMap; + typedef stdvector::fwd ChunkList; + typedef stdvector::fwd ServerChunkList; + typedef stdset::fwd ChunkSet; + +protected: + + virtual void createChunk (int x, int z, int chunkSize, unsigned hasLargerNeighborFlags); + virtual void removeUnnecessaryChunk (); + virtual void addChunk (Chunk* chunk, int chunkSize); + virtual const Chunk* findChunk (int x, int z, int chunkSize) const; + virtual const Chunk* findFirstRenderableChunk (int x, int z) const; + virtual const Chunk* findAnyChunk () const; + virtual uint32 computeChunkMapKey (int x, int z) const; + virtual void prepareForDelete (Chunk const * chunk); + void generateBetween(Vector const & start_o, Vector const & end_o, ChunkList & chunkList); + bool collideChunkList(ChunkList const & chunkList, Vector const & start_o, Vector const & end_o, CollisionInfo & result) const; + +protected: + + ChunkMap* const m_chunkMap; + +private: + + class ChunkSphereExtentAccessor: public BaseSphereTreeAccessor + { + public: + + static Sphere const getExtent (Chunk const * chunk); + static char const * getDebugName (Chunk const * chunk); + }; + + class CollisionChunkSorter; + +private: + + ServerProceduralTerrainAppearance (); + ServerProceduralTerrainAppearance (const ServerProceduralTerrainAppearance&); + ServerProceduralTerrainAppearance& operator= (const ServerProceduralTerrainAppearance&); + +private: + + int m_chunkMapKeyOffset; + + ServerChunkList* const m_highUsedChunkList; + ServerChunkList* const m_lowUsedChunkList; + ServerChunkList* const m_unusedChunkList; + ChunkList* const m_invalidateChunkList; + ChunkSet* const m_chunksCreatedThisFrame; + + SphereTree m_sphereTree; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.cpp new file mode 100644 index 00000000..c3a6e537 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.cpp @@ -0,0 +1,78 @@ +//=================================================================== +// +// ServerProceduralTerrainAppearanceTemplate.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "sharedTerrain/ServerProceduralTerrainAppearance.h" + +//=================================================================== + +void ServerProceduralTerrainAppearanceTemplate::install () +{ + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportInstall (), ("ServerProceduralTerrainAppearanceTemplate::install\n")); + + AppearanceTemplateList::assignBinding (TAG (M,P,T,A), ServerProceduralTerrainAppearanceTemplate::create); + AppearanceTemplateList::assignBinding (TAG (P,T,A,T), ServerProceduralTerrainAppearanceTemplate::create); + + ExitChain::add (remove, "ServerProceduralTerrainAppearanceTemplate::remove"); +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearanceTemplate::remove () +{ + AppearanceTemplateList::removeBinding (TAG (M,P,T,A)); + AppearanceTemplateList::removeBinding (TAG (P,T,A,T)); +} + +//------------------------------------------------------------------- + +AppearanceTemplate* ServerProceduralTerrainAppearanceTemplate::create (const char* filename, Iff* iff) +{ + return new ServerProceduralTerrainAppearanceTemplate (filename, iff); +} + +//=================================================================== + +ServerProceduralTerrainAppearanceTemplate::ServerProceduralTerrainAppearanceTemplate (const char* filename, Iff* iff) : + ProceduralTerrainAppearanceTemplate (filename, iff, false, 0, 2) +{ + unsigned mapsToSample = + TGM_vertexPosition + | TGM_shader + | TGM_passable + | TGM_exclude + ; + + if (getLegacyMode()) + { + mapsToSample|=TGM_floraStaticCollidable; + } + + m_terrainGenerator->setMapsToSample(mapsToSample); +} + +//------------------------------------------------------------------- + +ServerProceduralTerrainAppearanceTemplate::~ServerProceduralTerrainAppearanceTemplate () +{ +} + +//------------------------------------------------------------------- + +Appearance* ServerProceduralTerrainAppearanceTemplate::createAppearance () const +{ + return new ServerProceduralTerrainAppearance (this); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.h new file mode 100644 index 00000000..3d5471a8 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearanceTemplate.h @@ -0,0 +1,50 @@ +//=================================================================== +// +// ServerProceduralTerrainAppearanceTemplate.h +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_ServerProceduralTerrainAppearanceTemplate_h +#define INCLUDED_ServerProceduralTerrainAppearanceTemplate_h + +//=================================================================== + +#include "sharedTerrain/ProceduralTerrainAppearanceTemplate.h" + +class Iff; + +//=================================================================== + +class ServerProceduralTerrainAppearanceTemplate : public ProceduralTerrainAppearanceTemplate +{ +public: + + static void install (); + + static AppearanceTemplate* create (const char* filename, Iff* iff); + +public: + + ServerProceduralTerrainAppearanceTemplate (const char* filename, Iff* iff); + virtual ~ServerProceduralTerrainAppearanceTemplate (); + + virtual Appearance* createAppearance () const; + +private: + + static void remove (); + +private: + + ServerProceduralTerrainAppearanceTemplate (); + ServerProceduralTerrainAppearanceTemplate (const ServerProceduralTerrainAppearanceTemplate&); + ServerProceduralTerrainAppearanceTemplate& operator= (const ServerProceduralTerrainAppearanceTemplate&); +}; + +//=================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.cpp new file mode 100644 index 00000000..7a0c1205 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.cpp @@ -0,0 +1,334 @@ +//================================================================== +// +// ServerProceduralTerrainAppearance_Cache.cpp +// asommers +// +// copyright 2002, sony online entertainment +// +//================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerProceduralTerrainAppearance_Cache.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedMath/Plane.h" +#include "sharedTerrain/ConfigSharedTerrain.h" + +#include +#include + +//================================================================== + +namespace ServerProceduralTerrainAppearanceCacheNamespace +{ + typedef std::vector*> VertexListList; + typedef std::vector*> PlaneListList; + typedef std::vector*> ShaderGroupList; + typedef std::vector*> FloraGroupList; + + bool ms_installed; + uint ms_preloadSize = 2048; + VertexListList* ms_vertexListList; + PlaneListList* ms_planeListList; + ShaderGroupList* ms_shaderMapList; + FloraGroupList* ms_floraMapList; + +#ifdef _DEBUG + bool ms_debugReport; +#endif + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + void debugDump (); + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + ArrayList* localCreateVertexList (const int size) + { + ArrayList* const vertexList = new ArrayList; + vertexList->preallocate (size, true); + + return vertexList; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + ArrayList* localCreatePlaneList (const int size) + { + ArrayList* const planeList = new ArrayList; + planeList->preallocate (size, true); + + return planeList; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Array2d* localCreateShaderMap (const int width, const int height) + { + Array2d* const map = new Array2d; + map->allocate (width, height); + + return map; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Array2d* localCreateFloraMap (const int width, const int height) + { + Array2d* const map = new Array2d; + map->allocate (width, height); + + return map; + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +} + +using namespace ServerProceduralTerrainAppearanceCacheNamespace; + +//================================================================== + +void ServerProceduralTerrainAppearance::Cache::install () +{ + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportInstall (), ("ServerProceduralTerrainAppearance::Cache::install\n")); + + DEBUG_FATAL (ms_installed, ("already installed")); + ms_installed = true; + + ms_preloadSize = static_cast (ConfigSharedTerrain::getMaximumNumberOfChunksAllowed ()); + + //-- can't precreate maps because we don't know what size they will be + ms_vertexListList = new VertexListList; + ms_planeListList = new PlaneListList; + ms_shaderMapList = new ShaderGroupList; + ms_floraMapList = new FloraGroupList; + +#ifdef _DEBUG + DebugFlags::registerFlag (ServerProceduralTerrainAppearanceCacheNamespace::ms_debugReport, "SharedTerrain", "reportServerProceduralTerrainAppearanceCache", ServerProceduralTerrainAppearanceCacheNamespace::debugDump); +#endif +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::remove () +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + ms_installed = false; + + //-- delete non-array lists +#define DELETE_SPECIFIC_LIST(a) { \ + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportLogPrint (), ("Terrain Cache %sList = %i\n", #a, ms_ ## a ## List->size ())); \ + std::for_each (ms_ ## a ## List->begin (), ms_ ## a ## List->end (), PointerDeleter ()); \ + delete ms_ ## a ## List; \ + ms_ ## a ## List = 0; \ + } + + DELETE_SPECIFIC_LIST (vertexList); + DELETE_SPECIFIC_LIST (planeList); + DELETE_SPECIFIC_LIST (shaderMap); + DELETE_SPECIFIC_LIST (floraMap); + +#ifdef _DEBUG + DebugFlags::unregisterFlag (ServerProceduralTerrainAppearanceCacheNamespace::ms_debugReport); +#endif +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::warm (const int vertexListSize, const int planeListSize, const int mapSize) +{ + NOT_NULL (ms_vertexListList); + ms_vertexListList->reserve (ms_preloadSize); + + NOT_NULL (ms_planeListList); + ms_planeListList->reserve (ms_preloadSize); + + NOT_NULL (ms_shaderMapList); + ms_shaderMapList->reserve (ms_preloadSize); + + NOT_NULL (ms_floraMapList); + ms_floraMapList->reserve (ms_preloadSize); + + uint i; + for (i = 0; i < ms_preloadSize; ++i) + { + ms_vertexListList->push_back (localCreateVertexList (vertexListSize)); + ms_planeListList->push_back (localCreatePlaneList (planeListSize)); + ms_shaderMapList->push_back (localCreateShaderMap (mapSize, mapSize)); + ms_floraMapList->push_back (localCreateFloraMap (mapSize, mapSize)); + } +} + +//------------------------------------------------------------------- + +ArrayList* ServerProceduralTerrainAppearance::Cache::createVertexList (const int size) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_vertexListList); + + ArrayList* vertexList = 0; + + //-- just take one off the list + if (!ms_vertexListList->empty ()) + { + vertexList = ms_vertexListList->back (); + ms_vertexListList->pop_back (); + } + else + { + //-- create one + vertexList = localCreateVertexList (size); + } + + NOT_NULL (vertexList); + + return vertexList; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::destroyVertexList (ArrayList* const vertexList) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_vertexListList); + + if (vertexList) + ms_vertexListList->push_back (vertexList); +} + +//------------------------------------------------------------------- + +ArrayList* ServerProceduralTerrainAppearance::Cache::createPlaneList (const int size) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_planeListList); + + ArrayList* planeList = 0; + + //-- just take one off the list + if (!ms_planeListList->empty ()) + { + planeList = ms_planeListList->back (); + ms_planeListList->pop_back (); + } + else + { + //-- create one + planeList = localCreatePlaneList (size); + } + + NOT_NULL (planeList); + + return planeList; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::destroyPlaneList (ArrayList* const planeList) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_planeListList); + + if (planeList) + ms_planeListList->push_back (planeList); +} + +//------------------------------------------------------------------- + +Array2d* ServerProceduralTerrainAppearance::Cache::createShaderMap (int width, int height) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_shaderMapList); + + Array2d* map = 0; + + //-- just take one off the list + if (!ms_shaderMapList->empty ()) + { + map = ms_shaderMapList->back (); + ms_shaderMapList->pop_back (); + } + else + { + //-- create one + map = localCreateShaderMap (width, height); + } + + NOT_NULL (map); + DEBUG_FATAL (width != map->getWidth () && height != map->getHeight (), ("ServerProceduralTerrainAppearance::Cache - cached map of wrong size")); + + return map; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::destroyShaderMap (Array2d* map) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_shaderMapList); + + if (map) + ms_shaderMapList->push_back (map); +} + +//------------------------------------------------------------------- + +Array2d* ServerProceduralTerrainAppearance::Cache::createFloraMap (int width, int height) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_floraMapList); + + Array2d* map = 0; + + //-- just take one off the list + if (!ms_floraMapList->empty ()) + { + map = ms_floraMapList->back (); + ms_floraMapList->pop_back (); + } + else + { + //-- create one + map = localCreateFloraMap (width, height); + } + + NOT_NULL (map); + DEBUG_FATAL (width != map->getWidth () && height != map->getHeight (), ("ServerProceduralTerrainAppearance::Cache - cached map of wrong size")); + + return map; +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearance::Cache::destroyFloraMap (Array2d* map) +{ + DEBUG_FATAL (!ms_installed, ("not installed")); + NOT_NULL (ms_floraMapList); + + if (map) + ms_floraMapList->push_back (map); +} + +//------------------------------------------------------------------- + +void ServerProceduralTerrainAppearanceCacheNamespace::debugDump () +{ +#ifdef _DEBUG + + DEBUG_FATAL (!ms_installed, ("not installed")); + + NOT_NULL (ms_vertexListList); + NOT_NULL (ms_planeListList); + NOT_NULL (ms_shaderMapList); + NOT_NULL (ms_floraMapList); + + DEBUG_REPORT_PRINT (ms_debugReport, ("vertexListList size = %i\n", ms_vertexListList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("planeListList size = %i\n", ms_planeListList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("shaderMapList size = %i\n", ms_shaderMapList->size ())); + DEBUG_REPORT_PRINT (ms_debugReport, ("floraMapList size = %i\n", ms_floraMapList->size ())); + +#endif +} + +//================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.h new file mode 100644 index 00000000..2917bae3 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerProceduralTerrainAppearance_Cache.h @@ -0,0 +1,50 @@ +//================================================================== +// +// ServerProceduralTerrainAppearance_Cache.h +// asommers +// +// copyright 2002, sony online entertainment +// +//================================================================== + +#ifndef INCLUDED_ServerProceduralTerrainAppearance_Cache_H +#define INCLUDED_ServerProceduralTerrainAppearance_Cache_H + +//================================================================== + +#include "sharedTerrain/ServerProceduralTerrainAppearance.h" + +//================================================================== + +class ServerProceduralTerrainAppearance::Cache +{ +public: + + static void install (); + static void remove (); + + static void warm (int vertexListSize, int planeListSize, int mapSize); + + static ArrayList* createVertexList (int size); + static void destroyVertexList (ArrayList* vertexList); + + static ArrayList* createPlaneList (int size); + static void destroyPlaneList (ArrayList* planeList); + + static Array2d* createShaderMap (int width, int height); + static void destroyShaderMap (Array2d* map); + + static Array2d* createFloraMap (int width, int height); + static void destroyFloraMap (Array2d* map); + +private: + + Cache (); + ~Cache (); + Cache (const Cache&); + Cache& operator= (const Cache&); +}; + +//================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.cpp new file mode 100644 index 00000000..2a275441 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.cpp @@ -0,0 +1,30 @@ +// ====================================================================== +// +// ServerSpaceTerrainAppearance.cpp +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerSpaceTerrainAppearance.h" + +#include "sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h" + +// ====================================================================== +// PUBLIC ServerSpaceTerrainAppearance +// ====================================================================== + +ServerSpaceTerrainAppearance::ServerSpaceTerrainAppearance(ServerSpaceTerrainAppearanceTemplate const * const serverSpaceTerrainAppearanceTemplate) : + SpaceTerrainAppearance(serverSpaceTerrainAppearanceTemplate) +{ +} + +// ---------------------------------------------------------------------- + +ServerSpaceTerrainAppearance::~ServerSpaceTerrainAppearance() +{ +} + +// ====================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.h new file mode 100644 index 00000000..94ddcca5 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearance.h @@ -0,0 +1,37 @@ +// ====================================================================== +// +// ServerSpaceTerrainAppearance.h +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_ServerSpaceTerrainAppearance_H +#define INCLUDED_ServerSpaceTerrainAppearance_H + +// ====================================================================== + +#include "sharedTerrain/SpaceTerrainAppearance.h" + +class ServerSpaceTerrainAppearanceTemplate; + +// ====================================================================== + +class ServerSpaceTerrainAppearance : public SpaceTerrainAppearance +{ +public: + + explicit ServerSpaceTerrainAppearance(ServerSpaceTerrainAppearanceTemplate const * serverSpaceTerrainAppearanceTemplate); + virtual ~ServerSpaceTerrainAppearance(); + +private: + + ServerSpaceTerrainAppearance(); + ServerSpaceTerrainAppearance(ServerSpaceTerrainAppearance const &); + ServerSpaceTerrainAppearance & operator=(ServerSpaceTerrainAppearance const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.cpp new file mode 100644 index 00000000..75a88767 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.cpp @@ -0,0 +1,67 @@ +// ====================================================================== +// +// ServerSpaceTerrainAppearanceTemplate.cpp +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h" + +#include "sharedFoundation/ExitChain.h" +#include "sharedObject/AppearanceTemplateList.h" +#include "sharedTerrain/ServerSpaceTerrainAppearance.h" + +// ====================================================================== +// STATIC PUBLIC ServerSpaceTerrainAppearanceTemplate +// ====================================================================== + +void ServerSpaceTerrainAppearanceTemplate::install() +{ + AppearanceTemplateList::assignBinding(cms_spaceTerrainAppearanceTemplateTag, ServerSpaceTerrainAppearanceTemplate::create); + + ExitChain::add(ServerSpaceTerrainAppearanceTemplate::remove, "ServerSpaceTerrainAppearanceTemplate::remove"); +} + +// ---------------------------------------------------------------------- + +AppearanceTemplate * ServerSpaceTerrainAppearanceTemplate::create(char const * const filename, Iff * const iff) +{ + return new ServerSpaceTerrainAppearanceTemplate(filename, iff); +} + +// ====================================================================== +// PUBLIC ServerSpaceTerrainAppearanceTemplate +// ====================================================================== + +ServerSpaceTerrainAppearanceTemplate::ServerSpaceTerrainAppearanceTemplate(char const * const filename, Iff * const iff) : + SpaceTerrainAppearanceTemplate(filename, iff) +{ +} + +// ---------------------------------------------------------------------- + +ServerSpaceTerrainAppearanceTemplate::~ServerSpaceTerrainAppearanceTemplate() +{ +} + +// ---------------------------------------------------------------------- + +Appearance * ServerSpaceTerrainAppearanceTemplate::createAppearance() const +{ + return new ServerSpaceTerrainAppearance(this); +} + +// ====================================================================== +// STATIC PRIVATE ServerSpaceTerrainAppearanceTemplate +// ====================================================================== + +void ServerSpaceTerrainAppearanceTemplate::remove() +{ + AppearanceTemplateList::removeBinding(cms_spaceTerrainAppearanceTemplateTag); +} + +// ====================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.h new file mode 100644 index 00000000..d4ecd470 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/ServerSpaceTerrainAppearanceTemplate.h @@ -0,0 +1,50 @@ +// ====================================================================== +// +// ServerSpaceTerrainAppearanceTemplate.h +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_ServerSpaceTerrainAppearanceTemplate_H +#define INCLUDED_ServerSpaceTerrainAppearanceTemplate_H + +// ====================================================================== + +#include "sharedTerrain/SpaceTerrainAppearanceTemplate.h" + +class Iff; + +// ====================================================================== + +class ServerSpaceTerrainAppearanceTemplate : public SpaceTerrainAppearanceTemplate +{ +public: + + static void install(); + + static AppearanceTemplate * create(char const * filename, Iff * iff); + +public: + + ServerSpaceTerrainAppearanceTemplate(char const * filename, Iff * iff); + virtual ~ServerSpaceTerrainAppearanceTemplate(); + + virtual Appearance * createAppearance() const; + +private: + + static void remove(); + +private: + + ServerSpaceTerrainAppearanceTemplate(); + ServerSpaceTerrainAppearanceTemplate(ServerSpaceTerrainAppearanceTemplate const &); + ServerSpaceTerrainAppearanceTemplate & operator=(ServerSpaceTerrainAppearanceTemplate const &); +}; + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.cpp new file mode 100644 index 00000000..4e503a34 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.cpp @@ -0,0 +1,38 @@ +// ====================================================================== +// +// SpaceTerrainAppearance.cpp +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/SpaceTerrainAppearance.h" + +#include "sharedTerrain/SpaceTerrainAppearanceTemplate.h" + +// ====================================================================== +// PUBLIC SpaceTerrainAppearance +// ====================================================================== + +SpaceTerrainAppearance::SpaceTerrainAppearance(SpaceTerrainAppearanceTemplate const * const spaceTerrainAppearanceTemplate) : + TerrainAppearance(spaceTerrainAppearanceTemplate) +{ +} + +// ---------------------------------------------------------------------- + +SpaceTerrainAppearance::~SpaceTerrainAppearance() +{ +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearance::getMapWidthInMeters() const +{ + SpaceTerrainAppearanceTemplate const * const stat = safe_cast(getAppearanceTemplate()); + return stat->getMapWidthInMeters(); +} + +// ====================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.h new file mode 100644 index 00000000..c8c3c659 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearance.h @@ -0,0 +1,39 @@ +// ====================================================================== +// +// SpaceTerrainAppearance.h +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SpaceTerrainAppearance_H +#define INCLUDED_SpaceTerrainAppearance_H + +// ====================================================================== + +#include "sharedTerrain/TerrainAppearance.h" + +class SpaceTerrainAppearanceTemplate; + +// ====================================================================== + +class SpaceTerrainAppearance : public TerrainAppearance +{ +public: + + SpaceTerrainAppearance(SpaceTerrainAppearanceTemplate const * spaceTerrainAppearanceTemplate); + virtual ~SpaceTerrainAppearance(); + + virtual float getMapWidthInMeters() const; + +private: + + SpaceTerrainAppearance(); + SpaceTerrainAppearance(SpaceTerrainAppearance const &); + SpaceTerrainAppearance & operator=(SpaceTerrainAppearance const &); +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.cpp new file mode 100644 index 00000000..a2333e10 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.cpp @@ -0,0 +1,565 @@ +// ====================================================================== +// +// SpaceTerrainAppearanceTemplate.cpp +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/SpaceTerrainAppearanceTemplate.h" + +#include "sharedFile/Iff.h" + +#include +#include + +// ====================================================================== + +namespace SpaceTerrainAppearanceTemplateNamespace +{ + Tag const TAG_AMBI = TAG(A,M,B,I); + Tag const TAG_CELE = TAG(C,E,L,E); + Tag const TAG_CLEA = TAG(C,L,E,A); + Tag const TAG_DIST = TAG(D,I,S,T); + Tag const TAG_DUST = TAG(D,U,S,T); + Tag const TAG_ENVI = TAG(E,N,V,I); + Tag const TAG_FOG = TAG3(F,O,G); + Tag const TAG_PARA = TAG(P,A,R,A); + Tag const TAG_PLAN = TAG(P,L,A,N); + Tag const TAG_STAR = TAG(S,T,A,R); + Tag const TAG_SKYB = TAG(S,K,Y,B); +} + +using namespace SpaceTerrainAppearanceTemplateNamespace; + +// ====================================================================== +// PUBLIC SpaceTerrainAppearanceTemplate +// ====================================================================== + +SpaceTerrainAppearanceTemplate::SpaceTerrainAppearanceTemplate(char const * const filename, Iff * const iff) : + AppearanceTemplate(filename), + m_clearColor(), + m_ambientColor(), + m_lightDataList(new LightDataList), + m_environmentTextureName(), + m_fogEnabled(false), + m_fogColor(), + m_fogDensity(0.f), + m_numberOfStars(0), + m_starColorRampName(), + m_numberOfDust(0), + m_dustRadius(0.f), + m_skyBoxCubeMap(false), + m_skyBoxTextureNameMask(), + m_celestialDataList(new CelestialDataList), + m_distantAppearanceDataList(new DistantAppearanceDataList), + m_mapWidthInMeters(16384.0f) +{ + NOT_NULL(iff); + load(*iff); +} + +// ---------------------------------------------------------------------- + +SpaceTerrainAppearanceTemplate::~SpaceTerrainAppearanceTemplate() +{ + delete m_lightDataList; + delete m_celestialDataList; + delete m_distantAppearanceDataList; +} + +// ---------------------------------------------------------------------- + +PackedRgb const & SpaceTerrainAppearanceTemplate::getClearColor() const +{ + return m_clearColor; +} + +// ---------------------------------------------------------------------- + +VectorArgb const & SpaceTerrainAppearanceTemplate::getAmbientColor() const +{ + return m_ambientColor; +} + +// ---------------------------------------------------------------------- + +int SpaceTerrainAppearanceTemplate::getNumberOfParallelLights() const +{ + NOT_NULL(m_lightDataList); + return static_cast(m_lightDataList->size()); +} + +// ---------------------------------------------------------------------- + +VectorArgb const & SpaceTerrainAppearanceTemplate::getParallelLightDiffuseColor(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfParallelLights()); + return (*m_lightDataList)[static_cast(index)].m_diffuseColor; +} + +// ---------------------------------------------------------------------- + +VectorArgb const & SpaceTerrainAppearanceTemplate::getParallelLightSpecularColor(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfParallelLights()); + return (*m_lightDataList)[static_cast(index)].m_specularColor; +} + +// ---------------------------------------------------------------------- + +Vector const & SpaceTerrainAppearanceTemplate::getParallelLightDirection_w(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfParallelLights()); + return (*m_lightDataList)[static_cast(index)].m_direction_w; +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getEnvironmentTextureName() const +{ + return m_environmentTextureName; +} + +// ---------------------------------------------------------------------- + +bool SpaceTerrainAppearanceTemplate::getFogEnabled() const +{ + return m_fogEnabled; +} + +// ---------------------------------------------------------------------- + +PackedArgb const & SpaceTerrainAppearanceTemplate::getFogColor() const +{ + return m_fogColor; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getFogDensity() const +{ + return m_fogDensity; +} + +// ---------------------------------------------------------------------- + +int SpaceTerrainAppearanceTemplate::getNumberOfStars() const +{ + return m_numberOfStars; +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getStarColorRampName() const +{ + return m_starColorRampName; +} + +// ---------------------------------------------------------------------- + +int SpaceTerrainAppearanceTemplate::getNumberOfDust() const +{ + return m_numberOfDust; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getDustRadius() const +{ + return m_dustRadius; +} + +// ---------------------------------------------------------------------- + +bool SpaceTerrainAppearanceTemplate::getSkyBoxCubeMap() const +{ + return m_skyBoxCubeMap; +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getSkyBoxTextureNameMask() const +{ + return m_skyBoxTextureNameMask; +} + +// ---------------------------------------------------------------------- + +int SpaceTerrainAppearanceTemplate::getNumberOfDistantAppearances() const +{ + NOT_NULL(m_distantAppearanceDataList); + return static_cast(m_distantAppearanceDataList->size()); +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getDistantAppearanceTemplateName(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_appearanceTemplateName; +} + +// ---------------------------------------------------------------------- + +Vector const & SpaceTerrainAppearanceTemplate::getDistantAppearanceDirection_w(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_direction_w; +} + +// ---------------------------------------------------------------------- + +Vector const & SpaceTerrainAppearanceTemplate::getDistantAppearanceOrientation_w(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_orientation_w; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getPlanetHaloRoll(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_haloRoll; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getPlanetHaloScale(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_haloScale; +} + +//---------------------------------------------------------------------- + +bool SpaceTerrainAppearanceTemplate::isDistantAppearanceInfiniteDistance(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfDistantAppearances()); + return (*m_distantAppearanceDataList)[static_cast(index)].m_infiniteDistance; +} + +// ---------------------------------------------------------------------- + +int SpaceTerrainAppearanceTemplate::getNumberOfCelestials() const +{ + NOT_NULL(m_celestialDataList); + return static_cast(m_celestialDataList->size()); +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getCelestialBackShaderTemplateName(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCelestials()); + return (*m_celestialDataList)[static_cast(index)].m_backShaderTemplateName; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getCelestialBackSize(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCelestials()); + return (*m_celestialDataList)[static_cast(index)].m_backSize; +} + +// ---------------------------------------------------------------------- + +CrcString const & SpaceTerrainAppearanceTemplate::getCelestialFrontShaderTemplateName(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCelestials()); + return (*m_celestialDataList)[static_cast(index)].m_frontShaderTemplateName; +} + +// ---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getCelestialFrontSize(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCelestials()); + return (*m_celestialDataList)[static_cast(index)].m_frontSize; +} + +// ---------------------------------------------------------------------- + +Vector const & SpaceTerrainAppearanceTemplate::getCelestialDirection_w(int const index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, index, getNumberOfCelestials()); + return (*m_celestialDataList)[static_cast(index)].m_direction_w; +} + +// ====================================================================== +// PROTECTED SpaceTerrainAppearanceTemplate +// ====================================================================== + +Tag const SpaceTerrainAppearanceTemplate::cms_spaceTerrainAppearanceTemplateTag = TAG(S,T,A,T); + +// ====================================================================== +// PRIVATE SpaceTerrainAppearanceTemplate +// ====================================================================== + +void SpaceTerrainAppearanceTemplate::load(Iff & iff) +{ + iff.enterForm(cms_spaceTerrainAppearanceTemplateTag); + + switch(iff.getCurrentName()) + { + case TAG_0000: + load_0000(iff); + break; + + default: + { + char tagBuffer[5]; + ConvertTagToString(iff.getCurrentName(), tagBuffer); + + char buffer[128]; + iff.formatLocation(buffer, sizeof(buffer)); + + FATAL(true, ("SpaceTerrainAppearanceTemplate::load: unsupported version tag %s/%s", buffer, tagBuffer)); + } + break; + } + + iff.exitForm(cms_spaceTerrainAppearanceTemplateTag); +} + +// ---------------------------------------------------------------------- + +void SpaceTerrainAppearanceTemplate::load_0000(Iff & iff) +{ + iff.enterForm(TAG_0000); + + while (iff.getNumberOfBlocksLeft()) + { + switch (iff.getCurrentName()) + { + case TAG_INFO: + { + iff.enterForm(TAG_INFO); + { + iff.enterChunk(TAG_0000); + { + m_mapWidthInMeters = iff.read_float(); + } + iff.exitChunk(TAG_0000); + } + iff.exitForm(TAG_INFO); + } + break; + + case TAG_CLEA: + { + iff.enterForm(TAG_CLEA); + iff.enterChunk(TAG_0000); + + m_clearColor.r = static_cast(clamp(0.f, iff.read_float(), 1.f) * 255.f); + m_clearColor.g = static_cast(clamp(0.f, iff.read_float(), 1.f) * 255.f); + m_clearColor.b = static_cast(clamp(0.f, iff.read_float(), 1.f) * 255.f); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_CLEA); + } + break; + + case TAG_AMBI: + { + iff.enterForm(TAG_AMBI); + iff.enterChunk(TAG_0000); + + m_ambientColor = iff.read_floatVectorArgb(); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_AMBI); + } + break; + + case TAG_PARA: + { + iff.enterForm(TAG_PARA); + iff.enterChunk(TAG_0000); + + LightData lightData; + lightData.m_dot3 = iff.read_bool8(); + lightData.m_diffuseColor = iff.read_floatVectorArgb(); + lightData.m_specularColor = iff.read_floatVectorArgb(); + lightData.m_direction_w = iff.read_floatVector(); + m_lightDataList->push_back(lightData); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_PARA); + } + break; + + case TAG_ENVI: + { + iff.enterForm(TAG_ENVI); + iff.enterChunk(TAG_0000); + + std::string environmentTextureName; + iff.read_string(environmentTextureName); + m_environmentTextureName.set(environmentTextureName.c_str(), true); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_ENVI); + } + break; + + case TAG_FOG: + { + iff.enterForm(TAG_FOG); + iff.enterChunk(TAG_0000); + + m_fogEnabled = true; + VectorArgb const fogColor = iff.read_floatVectorArgb(); + m_fogColor.setArgb(fogColor); + m_fogDensity = fogColor.a; + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_FOG); + } + break; + + case TAG_STAR: + { + iff.enterForm(TAG_STAR); + iff.enterChunk(TAG_0000); + + std::string starColorRampName; + iff.read_string(starColorRampName); + m_starColorRampName.set(starColorRampName.c_str(), true); + + m_numberOfStars = iff.read_int32(); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_STAR); + } + break; + + case TAG_DUST: + { + iff.enterForm(TAG_DUST); + iff.enterChunk(TAG_0000); + + m_numberOfDust = iff.read_int32(); + m_dustRadius = iff.read_float(); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_DUST); + } + break; + + case TAG_SKYB: + { + iff.enterForm(TAG_SKYB); + iff.enterChunk(TAG_0000); + + m_skyBoxCubeMap = iff.read_bool8(); + + std::string textureNameMask; + iff.read_string(textureNameMask); + m_skyBoxTextureNameMask.set(textureNameMask.c_str(), true); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_SKYB); + } + break; + + case TAG_DIST: + { + iff.enterForm(TAG_DIST); + iff.enterChunk(TAG_0000); + + DistantAppearanceData distantAppearanceData; + std::string appearanceTemplateName; + iff.read_string(appearanceTemplateName); + distantAppearanceData.m_appearanceTemplateName.set(appearanceTemplateName.c_str(), true); + distantAppearanceData.m_direction_w = iff.read_floatVector(); + distantAppearanceData.m_orientation_w.x = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_orientation_w.y = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_orientation_w.z = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_haloRoll = 0.f; + distantAppearanceData.m_haloScale = 1.f; + distantAppearanceData.m_infiniteDistance = (iff.read_int8() != 0); + m_distantAppearanceDataList->push_back(distantAppearanceData); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_DIST); + } + break; + + case TAG_PLAN: + { + iff.enterForm(TAG_PLAN); + iff.enterChunk(TAG_0000); + + DistantAppearanceData distantAppearanceData; + std::string appearanceTemplateName; + iff.read_string(appearanceTemplateName); + distantAppearanceData.m_appearanceTemplateName.set(appearanceTemplateName.c_str(), true); + distantAppearanceData.m_direction_w = iff.read_floatVector(); + distantAppearanceData.m_orientation_w.x = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_orientation_w.y = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_orientation_w.z = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_haloRoll = convertDegreesToRadians(iff.read_float()); + distantAppearanceData.m_haloScale = iff.read_float(); + distantAppearanceData.m_infiniteDistance = (iff.read_int8() != 0); + m_distantAppearanceDataList->push_back(distantAppearanceData); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_PLAN); + } + break; + + case TAG_CELE: + { + iff.enterForm(TAG_CELE); + iff.enterChunk(TAG_0000); + + CelestialData celestialData; + std::string shaderTemplateName; + iff.read_string(shaderTemplateName); + celestialData.m_backShaderTemplateName.set(shaderTemplateName.c_str(), true); + celestialData.m_backSize = iff.read_float(); + iff.read_string(shaderTemplateName); + celestialData.m_frontShaderTemplateName.set(shaderTemplateName.c_str(), true); + celestialData.m_frontSize = iff.read_float(); + celestialData.m_direction_w = iff.read_floatVector(); + m_celestialDataList->push_back(celestialData); + + iff.exitChunk(TAG_0000); + iff.exitForm(TAG_CELE); + } + break; + + default: + { +#ifdef _DEBUG + char tagBuffer[5]; + ConvertTagToString(iff.getCurrentName(), tagBuffer); + + char buffer[128]; + iff.formatLocation(buffer, sizeof(buffer)); + + DEBUG_WARNING(true, ("SpaceTerrainAppearanceTemplate::load: skipping unknown chunk type %s/%s", buffer, tagBuffer)); +#endif + + IGNORE_RETURN(iff.goForward()); + } + break; + } + } + + iff.exitForm(TAG_0000); +} + +//---------------------------------------------------------------------- + +float SpaceTerrainAppearanceTemplate::getMapWidthInMeters() const +{ + return m_mapWidthInMeters; +} + +// ====================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.h b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.h new file mode 100644 index 00000000..a7ec57f8 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/SpaceTerrainAppearanceTemplate.h @@ -0,0 +1,160 @@ +// ====================================================================== +// +// SpaceTerrainAppearanceTemplate.h +// asommers +// +// copyright 2004, sony online entertainment +// +// ====================================================================== + +#ifndef INCLUDED_SpaceTerrainAppearanceTemplate_H +#define INCLUDED_SpaceTerrainAppearanceTemplate_H + +// ====================================================================== + +#include "sharedFoundation/PersistentCrcString.h" +#include "sharedFoundation/Tag.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedMath/PackedArgb.h" +#include "sharedMath/PackedRgb.h" +#include "sharedMath/Vector.h" +#include "sharedMath/VectorArgb.h" + +class Iff; + +// ====================================================================== + +class SpaceTerrainAppearanceTemplate : public AppearanceTemplate +{ +public: + + SpaceTerrainAppearanceTemplate(char const * filename, Iff * iff); + virtual ~SpaceTerrainAppearanceTemplate() = 0; + + PackedRgb const & getClearColor() const; + + VectorArgb const & getAmbientColor() const; + + int getNumberOfParallelLights() const; + VectorArgb const & getParallelLightDiffuseColor(int index) const; + VectorArgb const & getParallelLightSpecularColor(int index) const; + Vector const & getParallelLightDirection_w(int index) const; + + CrcString const & getEnvironmentTextureName() const; + + bool getFogEnabled() const; + PackedArgb const & getFogColor() const; + float getFogDensity() const; + + int getNumberOfStars() const; + CrcString const & getStarColorRampName() const; + + int getNumberOfDust() const; + float getDustRadius() const; + + bool getSkyBoxCubeMap() const; + CrcString const & getSkyBoxTextureNameMask() const; + + int getNumberOfDistantAppearances() const; + CrcString const & getDistantAppearanceTemplateName(int index) const; + Vector const & getDistantAppearanceDirection_w(int index) const; + Vector const & getDistantAppearanceOrientation_w(int index) const; + float getPlanetHaloRoll(int index) const; + float getPlanetHaloScale(int index) const; + bool isDistantAppearanceInfiniteDistance(int index) const; + + int getNumberOfCelestials() const; + CrcString const & getCelestialBackShaderTemplateName(int index) const; + float getCelestialBackSize(int index) const; + CrcString const & getCelestialFrontShaderTemplateName(int index) const; + float getCelestialFrontSize(int index) const; + Vector const & getCelestialDirection_w(int index) const; + + float getMapWidthInMeters() const; + +protected: + + static Tag const cms_spaceTerrainAppearanceTemplateTag; + +private: + + struct LightData + { + bool m_dot3; + VectorArgb m_diffuseColor; + VectorArgb m_specularColor; + Vector m_direction_w; + }; + + struct DistantAppearanceData + { + PersistentCrcString m_appearanceTemplateName; + Vector m_direction_w; + Vector m_orientation_w; + float m_haloRoll; + float m_haloScale; + bool m_infiniteDistance; + + private: + + DistantAppearanceData operator=(DistantAppearanceData const & rhs); + }; + + struct CelestialData + { + PersistentCrcString m_backShaderTemplateName; + float m_backSize; + PersistentCrcString m_frontShaderTemplateName; + float m_frontSize; + Vector m_direction_w; + + private: + + CelestialData operator=(CelestialData const & rhs); + }; + +private: + + SpaceTerrainAppearanceTemplate(); + SpaceTerrainAppearanceTemplate(SpaceTerrainAppearanceTemplate const &); + SpaceTerrainAppearanceTemplate & operator=(SpaceTerrainAppearanceTemplate const &); + + void load(Iff & iff); + void load_0000(Iff & iff); + +private: + + PackedRgb m_clearColor; + + VectorArgb m_ambientColor; + + typedef stdvector::fwd LightDataList; + LightDataList * const m_lightDataList; + + PersistentCrcString m_environmentTextureName; + + bool m_fogEnabled; + PackedArgb m_fogColor; + float m_fogDensity; + + int m_numberOfStars; + PersistentCrcString m_starColorRampName; + + int m_numberOfDust; + float m_dustRadius; + + bool m_skyBoxCubeMap; + PersistentCrcString m_skyBoxTextureNameMask; + + typedef stdvector::fwd CelestialDataList; + CelestialDataList * const m_celestialDataList; + + typedef stdvector::fwd DistantAppearanceDataList; + DistantAppearanceDataList * const m_distantAppearanceDataList; + + float m_mapWidthInMeters; +}; + +// ====================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.cpp new file mode 100644 index 00000000..adc87c0f --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.cpp @@ -0,0 +1,457 @@ +//=================================================================== +// +// TerrainAppearance.cpp +// asommers 7-6-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainAppearance.h" + +#include "sharedCollision/CollisionInfo.h" +#include "sharedMath/Sphere.h" +#include "sharedObject/Object.h" +#include "sharedObject/ObjectList.h" + +//=================================================================== +// PUBLIC TerrainAppearance +//=================================================================== + +TerrainAppearance::TerrainAppearance (const AppearanceTemplate* newAppearanceTemplate) : + Appearance (newAppearanceTemplate), + m_referenceObjectList (NON_NULL (new ObjectList (10))) +{ +} + +//------------------------------------------------------------------- + +TerrainAppearance::~TerrainAppearance () +{ + delete m_referenceObjectList; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::collide(Vector const & /*start_o*/, Vector const & /*end_o*/, CollideParameters const & /*collideParameters*/, CollisionInfo & /*result*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::collideObjects (const Vector& /*start_o*/, const Vector& /*end_o*/, CollisionInfo& /*result*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::approximateCollideObjects (const Vector& /*start_o*/, const Vector& /*end_o*/, CollisionInfo& /*result*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getPauseEnvironment () const +{ + return false; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::setPauseEnvironment (bool const /*pauseEnvironment*/) +{ +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getEnvironmentCycleTime () const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +const PackedRgb TerrainAppearance::getClearColor () const +{ + return PackedRgb::solidBlack; +} + +//------------------------------------------------------------------- + +const PackedRgb TerrainAppearance::getFogColor () const +{ + return PackedRgb::solidBlack; +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getFogDensity () const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::getTime (int& /*hour*/, int& /*minute*/) const +{ +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getTime () const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::setTime (float /*time*/, bool /*force*/) +{ +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::isDay () const +{ + return true; +} + +//---------------------------------------------------------------------- + +bool TerrainAppearance::isTimeLocked() const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getHeight (const Vector& /*position_o*/, float& /*height*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getHeight (const Vector& /*position_o*/, float& /*height*/, Vector& /*normal*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getHeightForceChunkCreation (const Vector& /*position_o*/, float& /*height*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +const ObjectTemplate* TerrainAppearance::getSurfaceProperties (const Vector& /*position_o*/) const +{ + return 0; +} + +//------------------------------------------------------------------- + +int TerrainAppearance::getTerrainType (const Vector& /*position_o*/) const +{ + return 0; +} + +//----------------------------------------------------------------- + +bool TerrainAppearance::getWaterHeight (const Vector& /*position_o*/, float& /*height*/) const +{ + return false; +} + +//----------------------------------------------------------------- + +bool TerrainAppearance::getWaterHeight (const Vector& /*position_o*/, float& /*height*/, TerrainGeneratorWaterType& /*waterType*/, bool /*ignoreNonTransparentWater*/) const +{ + return false; +} + +//----------------------------------------------------------------- + +TerrainGeneratorWaterType TerrainAppearance::getWaterType (const Vector& /*position_w*/) const +{ + return TGWT_invalid; +} + +//----------------------------------------------------------------- + +bool TerrainAppearance::getWater (const Rectangle2d& /*rectangle*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getSlope (const Rectangle2d& /*rectangle*/) const +{ + return false; +} + +//---------------------------------------------------------------------- + +bool TerrainAppearance::isPassable(Vector const & /*position_w*/) const +{ + return true; +} + +//---------------------------------------------------------------------- + +bool TerrainAppearance::isPassableForceChunkCreation(Vector const & /*position_w*/) const +{ + return true; +} + +//---------------------------------------------------------------------- + +bool TerrainAppearance::hasPassableAffectors() const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getWater (const int /*chunkX*/, const int /*chunkZ*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::getSlope (const int /*chunkX*/, const int /*chunkZ*/) const +{ + return false; +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getMapWidthInMeters () const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getChunkWidthInMeters () const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +int TerrainAppearance::getNumberOfChunks () const +{ + return 0; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::hasHighLevelOfDetailTerrain (const Vector& /*position_o*/) const +{ + return true; +} + +//------------------------------------------------------------------- + +int TerrainAppearance::calculateChunkX (float) const +{ + return 0; +} + +//------------------------------------------------------------------- + +int TerrainAppearance::calculateChunkZ (float) const +{ + return 0; +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getChunkHeight (const int /*chunkX*/, const int /*chunkZ*/) const +{ + return 0.f; +} + +//------------------------------------------------------------------- + +const BoxExtent* TerrainAppearance::getChunkExtent (const Vector& /*position_o*/) const +{ + return 0; +} + +//------------------------------------------------------------------- + +const BoxExtent* TerrainAppearance::getChunkExtentForceChunkCreation (const Vector& /*position_o*/) const +{ + return 0; +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::collideForceChunkCreation(Vector const & /*start_o*/, Vector const & /*end_o*/, CollisionInfo & /*result*/) +{ + return false; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::preRender (const Camera* /*camera*/) const +{ +} + +//----------------------------------------------------------------- + +void TerrainAppearance::postRender () const +{ +} + +//----------------------------------------------------------------- + +void TerrainAppearance::addClearCollidableFloraObject (const Object* const /*object*/, const Vector& /*position_w*/, const float /*radius*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::removeClearCollidableFloraObject (const Object* const /*object*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::addClearNonCollidableFloraObject (const Object* const /*object*/, const ClearFloraEntryList& /*clearFloraEntryList*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::removeClearNonCollidableFloraObject (const Object* const /*object*/) +{ +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getHighLevelOfDetailThreshold () const +{ + return 1.f; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::setHighLevelOfDetailThreshold (const float /*highLevelOfDetailThreshold*/) +{ +} + +//------------------------------------------------------------------- + +float TerrainAppearance::getLevelOfDetailThreshold () const +{ + return 1.f; +} + +//------------------------------------------------------------------- + +void TerrainAppearance::setLevelOfDetailThreshold (const float /*levelOfDetailThreshold*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::getPolygonSoup (const Rectangle2d& /*extent2d_o*/, IndexedTriangleList& /*indexedTriangleList*/) const +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::invalidateRegion (const Rectangle2d& /*extent2d*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::addReferenceObject (const Object* const object) +{ + m_referenceObjectList->addObject (const_cast (object)); +} + +//------------------------------------------------------------------- + +void TerrainAppearance::removeReferenceObject (const Object* const object) +{ + m_referenceObjectList->removeObject (const_cast (object)); +} + +//------------------------------------------------------------------- + +void TerrainAppearance::removeAllReferenceObjects () +{ + m_referenceObjectList->removeAll (); +} + +//------------------------------------------------------------------- + +bool TerrainAppearance::isReferenceObject (const Object* const object) const +{ + return m_referenceObjectList->find (object); +} + +//------------------------------------------------------------------- + +void TerrainAppearance::drawExtents (const Vector& /*position_o*/) const +{ +} + +//------------------------------------------------------------------- + +void TerrainAppearance::debugDump () const +{ +#ifdef _DEBUG + DEBUG_REPORT_PRINT (true, ("-- TerrainAppearance\n")); + + DEBUG_REPORT_PRINT (true, ("numberOfReferenceObjects = %i\n", getNumberOfReferenceObjects ())); + + if (getNumberOfReferenceObjects ()) + { + const Object* const object = getReferenceObject (0); + if (object) + { + const Vector position_w = object->getPosition_w (); + DEBUG_REPORT_PRINT (true, ("referenceObject0Position = <%1.2f, %1.2f, %1.2f>\n", position_w.x, position_w.y, position_w.z)); + } + } +#endif +} + +//------------------------------------------------------------------- + +void TerrainAppearance::purgeChunks() +{ +} + +//=================================================================== +// PRIVATE TerrainAppearance +//=================================================================== + +int TerrainAppearance::getNumberOfReferenceObjects () const +{ + return m_referenceObjectList->getNumberOfObjects (); +} + +//------------------------------------------------------------------- + +const Object* TerrainAppearance::getReferenceObject (const int index) const +{ + return m_referenceObjectList->getObject (index); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.h b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.h new file mode 100644 index 00000000..4a554682 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainAppearance.h @@ -0,0 +1,126 @@ +//=================================================================== +// +// TerrainAppearance.h +// asommers 7-6-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_TerrainAppearance_H +#define INCLUDED_TerrainAppearance_H + +//=================================================================== + +#include "sharedMath/PackedRgb.h" +#include "sharedObject/Appearance.h" +#include "sharedTerrain/TerrainGeneratorType.h" + +class Camera; +class ObjectList; +class ObjectTemplate; +class Rectangle2d; + +//=================================================================== + +class TerrainAppearance : public Appearance +{ +public: + + explicit TerrainAppearance (const AppearanceTemplate* newAppearanceTemplate); + virtual ~TerrainAppearance (); + + //-- Appearance + virtual bool collide(Vector const & start_o, Vector const & end_o, CollideParameters const & collideParameters, CollisionInfo & result) const; + + //-- TerrainAppearance + virtual bool getHeight (const Vector& position_o, float& height) const; + virtual bool getHeight (const Vector& position_o, float& height, Vector& normal) const; + virtual bool getHeightForceChunkCreation (const Vector& position_o, float& height) const; + virtual const ObjectTemplate* getSurfaceProperties (const Vector& position_o) const; + virtual int getTerrainType (const Vector& position_o) const; + virtual bool getWaterHeight (const Vector& position_o, float& height) const; + virtual bool getWaterHeight (const Vector& position_o, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater=false) const; + virtual TerrainGeneratorWaterType getWaterType (const Vector& position_w) const; + virtual bool getWater (const Rectangle2d& rectangle) const; + virtual bool getSlope (const Rectangle2d& rectangle) const; + virtual bool getWater (int chunkX, int chunkZ) const; + virtual bool getSlope (int chunkX, int chunkZ) const; + virtual bool isPassable(Vector const & position_w) const; + virtual bool isPassableForceChunkCreation(Vector const & position_w) const; + virtual bool hasPassableAffectors() const; + + virtual float getMapWidthInMeters () const; + virtual float getChunkWidthInMeters () const; + virtual int getNumberOfChunks () const; + virtual bool hasHighLevelOfDetailTerrain (const Vector& position_o) const; + virtual int calculateChunkX (float positionX_o) const; + virtual int calculateChunkZ (float positionZ_o) const; + virtual float getChunkHeight (int chunkX, int chunkZ) const; + virtual const BoxExtent* getChunkExtent (const Vector& position_o) const; + virtual const BoxExtent* getChunkExtentForceChunkCreation (const Vector& position_o) const; + virtual bool collideForceChunkCreation(Vector const & start_o, Vector const & end_o, CollisionInfo & result); + + virtual void preRender (const Camera* camera) const; + virtual void postRender () const; + + virtual bool collideObjects (const Vector& start_o, const Vector& end_o, CollisionInfo& result) const; + virtual bool approximateCollideObjects (const Vector& start_o, const Vector& end_o, CollisionInfo& result) const; + + virtual bool getPauseEnvironment () const; + virtual void setPauseEnvironment (bool pauseEnvironment); + virtual float getEnvironmentCycleTime () const; + virtual const PackedRgb getClearColor () const; + virtual const PackedRgb getFogColor () const; + virtual float getFogDensity () const; + virtual void getTime (int& hour, int& minute) const; + virtual float getTime () const; + virtual void setTime (float time, bool force); + virtual bool isDay () const; + virtual bool isTimeLocked() const; + + typedef stdvector >::fwd ClearFloraEntryList; + virtual void addClearCollidableFloraObject (const Object* object, const Vector& position_o, float radius); + virtual void removeClearCollidableFloraObject (const Object* object); + virtual void addClearNonCollidableFloraObject (const Object* object, const ClearFloraEntryList& clearFloraEntryList); + virtual void removeClearNonCollidableFloraObject (const Object* object); + + virtual float getHighLevelOfDetailThreshold () const; + virtual void setHighLevelOfDetailThreshold (float highLevelOfDetailThreshold); + virtual float getLevelOfDetailThreshold () const; + virtual void setLevelOfDetailThreshold (float levelOfDetailThreshold); + + virtual void getPolygonSoup (const Rectangle2d& extent2d_o, IndexedTriangleList& indexedTriangleList) const; + + virtual void invalidateRegion (const Rectangle2d& extent2d); + + void addReferenceObject (const Object* object); + int getNumberOfReferenceObjects () const; + void removeReferenceObject (const Object* object); + void removeAllReferenceObjects (); + bool isReferenceObject (const Object* object) const; + + //-- debugging + virtual void drawExtents (const Vector& position_o) const; + virtual void debugDump () const; + virtual void purgeChunks(); + +protected: + + const Object* getReferenceObject (int index) const; + +private: + + TerrainAppearance (); + TerrainAppearance (const TerrainAppearance&); + TerrainAppearance& operator= (const TerrainAppearance&); + +private: + + ObjectList* const m_referenceObjectList; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.cpp b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.cpp new file mode 100644 index 00000000..00f91425 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.cpp @@ -0,0 +1,1017 @@ +// ====================================================================== +// +// TerrainQuadTree.cpp +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainQuadTree.h" + +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/MemoryBlockManager.h" +#include "sharedMath/Vector2d.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" + +// ====================================================================== +/** +* Quadtree iteration orders depend on the following quadrant layout: +* 0 = northeast +* 1 = northwest +* 2 = southwest +* 3 = southeast +* +* like mathematical quadrants: +* +----------- +* | 1 | 0 | +* |____|____| +* | 2 | 3 | +* |____|____| +* +* -1 represents the current node processing +*/ + +const int TerrainQuadTree::IteratorConstants::ORDER_PRE[4] = { 0, 1, 2, 3 }; + +const int TerrainQuadTree::IteratorConstants::ORDER_ENE[4] = { 0, 3, 1, 2 }; +const int TerrainQuadTree::IteratorConstants::ORDER_NNE[4] = { 0, 1, 3, 2 }; +const int TerrainQuadTree::IteratorConstants::ORDER_NNW[4] = { 1, 0, 2, 3 }; +const int TerrainQuadTree::IteratorConstants::ORDER_WNW[4] = { 1, 2, 0, 3 }; +const int TerrainQuadTree::IteratorConstants::ORDER_WSW[4] = { 2, 1, 3, 0 }; +const int TerrainQuadTree::IteratorConstants::ORDER_SSW[4] = { 2, 3, 1, 0 }; +const int TerrainQuadTree::IteratorConstants::ORDER_SSE[4] = { 3, 2, 0, 1 }; +const int TerrainQuadTree::IteratorConstants::ORDER_ESE[4] = { 3, 0, 2, 1 }; + +/** +* +* +*/ + +const int * const TerrainQuadTree::IteratorConstants::HALF_QUADRANT_ORDERS[8] = +{ + TerrainQuadTree::IteratorConstants::ORDER_ENE, + TerrainQuadTree::IteratorConstants::ORDER_NNE, + TerrainQuadTree::IteratorConstants::ORDER_NNW, + TerrainQuadTree::IteratorConstants::ORDER_WNW, + TerrainQuadTree::IteratorConstants::ORDER_WSW, + TerrainQuadTree::IteratorConstants::ORDER_SSW, + TerrainQuadTree::IteratorConstants::ORDER_SSE, + TerrainQuadTree::IteratorConstants::ORDER_ESE +}; + +const int TerrainQuadTree::Node::REVERSE_DIRECTIONS[4] = +{ + TerrainQuadTree::Node::SOUTH, + TerrainQuadTree::Node::EAST, + TerrainQuadTree::Node::NORTH, + TerrainQuadTree::Node::WEST +}; + +const int TerrainQuadTree::Node::OPPOSITE_QUADRANTS[4] = +{ + TerrainQuadTree::Node::SOUTHWEST, + TerrainQuadTree::Node::SOUTHEAST, + TerrainQuadTree::Node::NORTHEAST, + TerrainQuadTree::Node::NORTHWEST +}; + +const int TerrainQuadTree::Node::OPPOSITE_HALFQUADRANTS[8] = +{ + TerrainQuadTree::Node::WSW, + TerrainQuadTree::Node::SSW, + TerrainQuadTree::Node::SSE, + TerrainQuadTree::Node::ESE, + TerrainQuadTree::Node::ENE, + TerrainQuadTree::Node::NNE, + TerrainQuadTree::Node::NNW, + TerrainQuadTree::Node::WNW +}; + +// ====================================================================== + +struct Wombat +{ + int outer [2]; // neighbors outside the parent quad + int inner [2]; // neighbors inside the parent quad + int child [2]; +}; + +//----------------------------------------------------------------- + +static const Wombat s_wombats[4] = +{ + { + {TerrainQuadTree::Node::NORTH,TerrainQuadTree::Node::EAST}, + {TerrainQuadTree::Node::SOUTH,TerrainQuadTree::Node::WEST}, + {TerrainQuadTree::Node::SOUTHEAST,TerrainQuadTree::Node::NORTHWEST}, + }, + { + {TerrainQuadTree::Node::NORTH,TerrainQuadTree::Node::WEST}, + {TerrainQuadTree::Node::SOUTH,TerrainQuadTree::Node::EAST}, + {TerrainQuadTree::Node::SOUTHWEST,TerrainQuadTree::Node::NORTHEAST}, + }, + { + {TerrainQuadTree::Node::SOUTH,TerrainQuadTree::Node::WEST}, + {TerrainQuadTree::Node::NORTH,TerrainQuadTree::Node::EAST}, + {TerrainQuadTree::Node::NORTHWEST,TerrainQuadTree::Node::SOUTHEAST}, + }, + { + {TerrainQuadTree::Node::SOUTH,TerrainQuadTree::Node::EAST}, + {TerrainQuadTree::Node::NORTH,TerrainQuadTree::Node::WEST}, + {TerrainQuadTree::Node::NORTHEAST,TerrainQuadTree::Node::SOUTHWEST}, + } +}; + +// ====================================================================== +// STATIC PUBLIC TerrainQuadTree::Node +// ====================================================================== + +MEMORY_BLOCK_MANAGER_IMPLEMENTATION_WITHOUT_INSTALL (TerrainQuadTree::Node, false, 256, 8, 0); + +//------------------------------------------------------------------- + +static bool ms_useDistance2d = false; + +void TerrainQuadTree::Node::install () +{ + installMemoryBlockManager (); +} + +//------------------------------------------------------------------- + +void TerrainQuadTree::Node::remove () +{ + removeMemoryBlockManager (); +} + +// ====================================================================== +// PUBLIC TerrainQuadTree::Node +// ====================================================================== +/** +* Create a node. +* @param newX the bottom left corner of the node in chunkspace. +* @param newY the bottom left corner of the node in chunkspace. +* @param newSize the width/height of the node in chunkspace. +*/ +TerrainQuadTree::Node::Node (const int x, const int z, const int size, const float minChunkWidthInMeters) : + m_x(static_cast(x)), + m_z(static_cast(z)), + m_size(static_cast(size)), + m_childIndex (0), + m_worldExtentInitialized (false), + m_selectedForRender (false), + m_outsideBuildRange (false), + m_minChunkWidthInMeters (minChunkWidthInMeters), + m_chunk (0), + m_parent (0), + m_numberOfChunks (0), + m_worldExtent () +{ + DEBUG_FATAL(x>=32768 || x<-32768, ("Chunkspace coordinates are limited to +/-32768")); + DEBUG_FATAL(z>=32768 || z<-32768, ("Chunkspace coordinates are limited to +/-32768")); + DEBUG_FATAL(m_size >= MAX_SIZE, ("Cannot create a node bigger than or equal to %d\n", MAX_SIZE)); + DEBUG_FATAL(m_size < 1, ("Minimum size of quad node is 1!\n")); + + m_subNodes[0] = m_subNodes[1] = m_subNodes[2] = m_subNodes[3] = 0; + clearHasLargerNeighbors (); + + Vector v; + v.x = getX() * m_minChunkWidthInMeters; + v.z = getZ() * m_minChunkWidthInMeters; + v.y = 0; + + m_worldExtent.setMin (v); + + v.x += (getSize() * m_minChunkWidthInMeters); + v.z += (getSize() * m_minChunkWidthInMeters); + v.y = 0; + + m_worldExtent.setMax (v); + m_worldExtent.calculateCenterAndRadius (); + + m_neighbors [0] = m_neighbors [1] = m_neighbors [2] = m_neighbors [3] = 0; +} + +//----------------------------------------------------------------- +/** +* The destructor deletes any chunk that is still on the node. +*/ + +TerrainQuadTree::Node::~Node () +{ + if (m_chunk) + delete m_chunk; + + m_chunk = 0; +} + + +//----------------------------------------------------------------- +/** +* destroyNode simply calls removeNode for the specified node, and then deletes the specified node. +* @param node The node to be removed. It is removed and deleted. This should be a leaf node without chunks, otherwise you will have a memory leak or worse. +*/ +void TerrainQuadTree::Node::destroyNode (TerrainQuadTree::Node * const node) +{ + removeNode (node); + delete node; +} + +//----------------------------------------------------------------- +/** +* removeNode detaches a node from the tree. Nothing is deleted. +* @param node The node to be detached. Node must be a direct child of this. +*/ +void TerrainQuadTree::Node::removeNode (TerrainQuadTree::Node * const node) +{ + DEBUG_FATAL (node->m_parent != this, ("Can only call removeNode for direct parent-child.\n")); + + for (int i = 0; i < 4; ++i) + { + if (node->m_neighbors [i]) + { + node->m_neighbors [i]->m_neighbors [REVERSE_DIRECTIONS [i]] = 0; + node->m_neighbors [i] = 0; + } + } + + Node * p = this; + + while (p) + { + p->m_numberOfChunks -= node->m_numberOfChunks; + p = p->m_parent; + } + + m_subNodes [node->m_childIndex] = 0; + node->m_numberOfChunks = 0; + node->m_parent = 0; +} + +//----------------------------------------------------------------- +/** +* attach a node to the tree at the specified position and quadrant. +* @param node the node to attach +* @param quadrant an index in [0-3]. +*/ +void TerrainQuadTree::Node::addNode (TerrainQuadTree::Node * const node, const int quadrant) +{ + NOT_NULL (node); + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, quadrant, 4); + DEBUG_FATAL(!nodeEncloses (node->getX (), node->getZ ()), ("attempt to add invalid subnode %d, %d {%d}\n", node->getX (), node->getZ (), node->getSize ())); + DEBUG_FATAL(quadrant<0 || quadrant>4, ("Illegal child index.")); + + node->m_childIndex = static_cast(quadrant); + node->m_parent = this; + m_subNodes [quadrant] = node; + + const Wombat & wb = s_wombats [quadrant]; + + for (int i = 0; i < 2; ++i) + { + const int outer = wb.outer [i]; + const int inner = wb.inner [i]; + + node->m_neighbors [outer] = + this->m_neighbors [outer] ? this->m_neighbors [outer]->getSubNode (wb.child [i]) : 0; + + if (node->m_neighbors [outer]) + { + const int rev = REVERSE_DIRECTIONS [outer]; + DEBUG_FATAL (node->m_neighbors [outer]->m_neighbors [rev], ("error inserting terrain node\n")); + node->m_neighbors [outer]->m_neighbors [rev] = node; + } + + node->m_neighbors [wb.inner [i]] = this->getSubNode (wb.child [i]); + + if (node->m_neighbors [inner]) + { + const int rev = REVERSE_DIRECTIONS [inner]; + node->m_neighbors [inner]->m_neighbors [rev] = node; + } + } +} + +//----------------------------------------------------------------- +/** +* Add a chunk to the tree in the appropriate position, creating any nodes and subnodes as necessary to contain it. +* @param newChunk the chunk to add to the tree. Currently all chunks are assumed to be of size 1. +*/ +TerrainQuadTree::Node * TerrainQuadTree::Node::addChunk (ProceduralTerrainAppearance::Chunk * const chunk, const int size) +{ + NOT_NULL (chunk); + + DEBUG_FATAL (!nodeEncloses (chunk->getChunkX (), chunk->getChunkZ ()), ("Error adding chunk to node -- chunk %d,%d does not fit in the tree!!\n", chunk->getChunkX (), chunk->getChunkZ ())); + + if (m_worldExtentInitialized) + m_worldExtent.grow (chunk->getBoxExtent ()); + else + { + // make sure the box extent of this quad node is at least as + // big as the node in 2d, with the appropriate y values + + Vector v = m_worldExtent.getMin (); + v.y = chunk->getBoxExtent ().getMin ().y; + + m_worldExtent.setMin (v); + + v = m_worldExtent.getMax (); + v.y = chunk->getBoxExtent ().getMax ().y; + + m_worldExtent.setMax (v); + + m_worldExtent.calculateCenterAndRadius (); + + m_worldExtentInitialized = true; + } + + m_numberOfChunks++; + + //-- hit the bottom, add the chunk + if (getSize() == size) + { + + DEBUG_FATAL ( m_chunk, ("Error adding chunk to node -- chunk is already in the tree!!\n")); + m_chunk = chunk; + return this; + } + + int which = getQuadrant (chunk->getChunkX (), chunk->getChunkZ ()); + + // add the node in the appropriate part of the array and the list + if (m_subNodes [which] == 0) + { + const int half = getSize() / 2; + + Node * fresh = new Node ( + (which == 2 || which == 1) ? getX() : getX() + half, + (which == 2 || which == 3) ? getZ() : getZ() + half, + half, + m_minChunkWidthInMeters); + + addNode (fresh, which); + } + + return m_subNodes [which]->addChunk (chunk, size); +} + +//----------------------------------------------------------------- +/** +* Remove all subtrees of this node. All subnodes are deleted. All chunks in the subtrees are deleted if indicated. +* The parents of this subnode DO NOT have their chunk counts updated apporpriately. +* @param deleteChunks if true, delete any chunks found in the tree. +*/ +int TerrainQuadTree::Node::internalRemoveSubNodes (const bool deleteChunks) +{ + int num_chunks_removed = 0; + + for (int i = 0; i < 4; ++i ) + { + Node * const snode = m_subNodes [i]; + + if (snode) + { + if (snode->m_chunk) + { + if (deleteChunks) + delete snode->m_chunk; + + snode->m_chunk = 0; + num_chunks_removed++; + } + + num_chunks_removed += snode->internalRemoveSubNodes (deleteChunks); + + for (int j = 0; j < 4; ++j) + { + if (snode->m_neighbors [j]) + { + snode->m_neighbors [j]->m_neighbors [REVERSE_DIRECTIONS [j]] = 0; + snode->m_neighbors [j] = 0; + } + } + + delete m_subNodes [i]; + m_subNodes [i] = 0; + } + } + + return num_chunks_removed; +} +//----------------------------------------------------------------- +/** +* Remove all subtrees of this node. All subnodes are deleted. All chunks in the subtrees are deleted if indicated. +* The parents of this chunk have their chunk counts updated appropriately. +* @param deleteChunks if true, delete any chunks found in the tree. +*/ + +int TerrainQuadTree::Node::removeSubNodes (const bool deleteChunks) +{ + if (getSize() == 1) + return 0; + + int num_chunks_removed = internalRemoveSubNodes (deleteChunks); + + //-- update m_numberOfChunks for this node and all its' parental units + Node * p = this; + + while (p) + { + p->m_numberOfChunks -= num_chunks_removed; + p = p->m_parent; + } + + return num_chunks_removed; +} + +//----------------------------------------------------------------- + +int TerrainQuadTree::Node::internalRemoveSubNodeChunks (const bool deleteChunks, const bool recurse) const +{ + int num_chunks_removed = 0; + + for (int i = 0; i < 4; ++i ) + { + if (m_subNodes[i]) + { + if (m_subNodes[i]->m_chunk) + { + if (deleteChunks) + delete m_subNodes[i]->m_chunk; + + m_subNodes[i]->m_chunk = 0; + num_chunks_removed++; + } + + if (recurse) + num_chunks_removed += m_subNodes [i]->internalRemoveSubNodeChunks (deleteChunks, recurse); + } + } + + return num_chunks_removed; +} + +//----------------------------------------------------------------- + +int TerrainQuadTree::Node::removeSubNodeChunks (const bool deleteChunks, const bool recurse) +{ + if (getSize() == 1) + return 0; + + int num_chunks_removed = internalRemoveSubNodeChunks (deleteChunks, recurse); + + //-- update m_numberOfChunks for this node and all its' parental units + Node * p = this; + + while (p) + { + p->m_numberOfChunks -= num_chunks_removed; + p = p->m_parent; + } + + return num_chunks_removed; + +} + +//----------------------------------------------------------------- +/** +* remove a chunk from the tree. It's former node is not deleted. uses findChunkNode. +* @param aChunk which chunk to remove +* @param deleteChunk delete the chunk or not +*/ +void TerrainQuadTree::Node::removeChunk (ProceduralTerrainAppearance::Chunk * const chunk, const bool deleteChunk) +{ + NOT_NULL (chunk); + + if (m_chunk == chunk) + { + if (deleteChunk) + delete m_chunk; + m_chunk = 0; + + Node * p = this; + + while (p) + { + p->m_numberOfChunks--; + p = p->m_parent; + } + + return; + } + + Node * node = findChunkNode (chunk, 0, 0, 0); + NOT_NULL (node); + + node->removeChunk (chunk, deleteChunk); +} + +//----------------------------------------------------------------- +/** +* pruneTree removes all subtrees which do not contain any chunks. All subtree nodes are deleted. +*/ +void TerrainQuadTree::Node::pruneTree () +{ + if (m_numberOfChunks == 0) + { + IGNORE_RETURN (removeSubNodes (false)); + return; + } + + for (int i = 0; i < 4; ++i) + { + if (m_subNodes[i]) + { + if (m_subNodes[i]->m_numberOfChunks == 0) + IGNORE_RETURN (m_subNodes[i]->removeSubNodes (false)); + else + m_subNodes[i]->pruneTree (); + } + } +} + +//----------------------------------------------------------------- +/** +* Find the leaf node which directly contains this chunk. +* +* @param aChunk the chunk to be located. If non null, the parameters ax and az are ignored. +* @param ax the chunkspace coordinate of the chunk to be located. Only used if param aChunk is null +* @param az the chunkspace coordinate of the chunk to be located. Only used if param aChunk is null +*/ +TerrainQuadTree::Node * TerrainQuadTree::Node::findChunkNode (const ProceduralTerrainAppearance::Chunk * const chunk, int x, int z, int size) +{ + Node * node = this; + + if (chunk) + { + x = chunk->getChunkX (); + z = chunk->getChunkZ (); + size = static_cast (chunk->getChunkWidthInMeters () / m_minChunkWidthInMeters); + } + + if (!node->nodeEncloses (x, z)) + return 0; + + while (node) + { + if (node->getSize() == size && node->getX() == x && node->getZ() == z) + return node; + + const int which = node->getQuadrant (x, z); + node = node->m_subNodes [which]; + } + + return 0; +} + +TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderablePeerNeighbor (const TerrainQuadTree::Node * const otherNode, const int dir) +{ + NOT_NULL (this); + NOT_NULL (otherNode); + + const int dir_offsets[4][2] = + { + // north + { 0, otherNode->getSize () }, + // west + { -otherNode->getSize (), 0}, + // south + { 0, -otherNode->getSize () }, + // east + { otherNode->getSize (), 0 }, + }; + + Node * neighbor = findFirstRenderableNode ( otherNode->getX() + dir_offsets[dir][0], + otherNode->getZ() + dir_offsets[dir][1]); + + if (neighbor && neighbor->nodeEncloses (otherNode->getX(), otherNode->getZ())) + neighbor = 0; + + return neighbor; +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderableLowerNeighbor (const TerrainQuadTree::Node * const otherNode, const int dir) +{ + NOT_NULL (this); + NOT_NULL (otherNode); + + const int halfSize = otherNode->getSize () / 2; + + const int dir_offsets[4][2][2] = + { + // north + { + { halfSize, otherNode->getSize () }, + { 0, otherNode->getSize () } + }, + // west + { + { -halfSize, halfSize }, + { -halfSize, 0 } + }, + // south + { + { 0, -halfSize }, + { halfSize, -halfSize } + }, + // east + { + { otherNode->getSize (), 0 }, + { otherNode->getSize (), halfSize } + }, + }; + + Node * neighbors [2]; + + neighbors [0] = findFirstRenderableNode ( otherNode->getX() + dir_offsets[dir][0][0], + otherNode->getZ() + dir_offsets[dir][0][1]); + + if (neighbors [0] && neighbors [0]->nodeEncloses (otherNode->getX(), otherNode->getZ())) + neighbors [0] = 0; + + neighbors [1] = findFirstRenderableNode ( otherNode->getX() + dir_offsets[dir][1][0], + otherNode->getZ() + dir_offsets[dir][1][1]); + + if (neighbors [1] && neighbors [1]->nodeEncloses (otherNode->getX(), otherNode->getZ())) + neighbors [1] = 0; + + if (neighbors [0] && (neighbors [1] == 0 || neighbors [0]->getSize () < neighbors [1]->getSize ())) + return neighbors [0]; + else + return neighbors [1]; +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Node * TerrainQuadTree::Node::findNode (const int ax, const int az, const int asize) +{ + DEBUG_FATAL (asize > getSize(), ("findNode whaa???")); + + if (!nodeEncloses (ax, az)) + return 0; + + Node * node = this; + + while (node) + { + if (node->getSize () == asize) + { + break; + } + + node = node->getSubNode (node->getQuadrant (ax, az)); + } + + return node; +} + +//----------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified position +*/ +const TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderableNode (const Vector& position) const +{ + const int ax = static_cast ((position.x >= 0 ? position.x : (position.x - m_minChunkWidthInMeters)) / m_minChunkWidthInMeters); + const int az = static_cast ((position.z >= 0 ? position.z : (position.z - m_minChunkWidthInMeters)) / m_minChunkWidthInMeters); + + return findFirstRenderableNode (ax, az); +} + +//----------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified position +*/ + +TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderableNode (const Vector& position) +{ + const int ax = static_cast ((position.x >= 0 ? position.x : (position.x - m_minChunkWidthInMeters)) / m_minChunkWidthInMeters); + const int az = static_cast ((position.z >= 0 ? position.z : (position.z - m_minChunkWidthInMeters)) / m_minChunkWidthInMeters); + + return findFirstRenderableNode (ax, az); +} + +//------------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified position +*/ +const TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderableNode (const int ax, const int az) const +{ + TerrainQuadTree::ConstIterator iter (this); + + const TerrainQuadTree::Node * node = 0; + + while ((node = iter.getCurNode ()) != 0) + { + if (node->isSelectedForRender ()) + { + if (node->nodeEncloses (ax, az)) + return node; + else + return 0; + } + + // TODO: no need to descend into all 4 quadrants... 1 is enough + + // descend front-to-back + IGNORE_RETURN (iter.descendOneChild (node->getQuadrant (ax, az))); + + } + + return 0; +} + +//----------------------------------------------------------------- +/** +* Obtain the first renderable chunk which contains the specified position +*/ +TerrainQuadTree::Node * TerrainQuadTree::Node::findFirstRenderableNode (const int ax, const int az) +{ + TerrainQuadTree::Iterator iter (this); + + TerrainQuadTree::Node * node = 0; + + while ((node = iter.getCurNode ()) != 0) + { + if (node->isSelectedForRender ()) + { + if (node->nodeEncloses (ax, az)) + return node; + else + return 0; + } + + // TODO: no need to descend into all 4 quadrants... 1 is enough + + // descend front-to-back + IGNORE_RETURN (iter.descendOneChild (node->getQuadrant (ax, az))); + + } + + return 0; +} + +//----------------------------------------------------------------- +/** +* hasChunk is a wrapper for findChunkNode +* +* @param aChunk the chunk to be located. If non null, the parameters ax and az are ignored. +* @param ax the chunkspace coordinate of the chunk to be located. Only used if param aChunk is null +* @param az the chunkspace coordinate of the chunk to be located. Only used if param aChunk is null +* @param chunkSize the relative size of the chunk in chunkspace. +*/ +bool TerrainQuadTree::Node::hasChunk (const ProceduralTerrainAppearance::Chunk * const chunk, const int x, const int z, const int size) +{ + return findChunkNode (chunk, x, z, size) != 0; +} + +//----------------------------------------------------------------- +/** +* Simple test in chunkspace. +*/ +bool TerrainQuadTree::Node::nodeEncloses (const int x, const int z) const +{ + return + x >= getX() && x < (getX() + getSize()) && + z >= getZ() && z < (getZ() + getSize()); +}; + +//----------------------------------------------------------------- +/** +* Determine what quadrant the given point is in, in relation to the center of this node. +*/ +int TerrainQuadTree::Node::getQuadrant (const int x, const int z) const +{ + const int half = getSize() / 2; + return getQuadrantTemplate ((x - getX()) - half, (z - getZ()) - half); +} + +//----------------------------------------------------------------- +/** +* Determine what quadrant the given point is in, in relation to the center of this node. +*/ +int TerrainQuadTree::Node::getQuadrant (const Vector & position) const +{ + const Vector & center = getBoxExtent ().getSphere ().getCenter (); + return getQuadrantTemplate (position.x - center.x, position.z - center.z); +} + +//----------------------------------------------------------------- +/** +* Determine what half-quadrant the given point is in, in relation to the center of this node. +* @param x the x position in chunkspace +* @param z the z position in chunkspace +*/ +int TerrainQuadTree::Node::getHalfQuadrant (const int x, const int z) const +{ + const int half = getSize() / 2; + return getHalfQuadrantTemplate ((x - getX()) - half, (z - getZ()) - half); + +} + +//----------------------------------------------------------------- +/** +* Determine what half-quadrant the given point is in, in relation to the center of this node. +* @param v the Vector position in worldspace +*/ +int TerrainQuadTree::Node::getHalfQuadrant (const Vector & v) const +{ + const Vector & center = getBoxExtent ().getSphere ().getCenter (); + return getHalfQuadrantTemplate (v.x - center.x, v.z - center.z); +} + +//----------------------------------------------------------------- + +float TerrainQuadTree::Node::getDistanceSquared (const Vector & position) const +{ + if (ms_useDistance2d) + { + const Vector& minimum = getBoxExtent ().getMin (); + const Vector& maximum = getBoxExtent ().getMax (); + const Rectangle2d rectangle (minimum.x, minimum.z, maximum.x, maximum.z); + const Vector2d position2d (position.x, position.z); + + if (rectangle.isWithin (position2d)) + return 0.f; + + Vector2d corner; + + if (position2d.x < rectangle.x0) + corner.x = rectangle.x0; + else + if (position2d.x > rectangle.x1) + corner.x = rectangle.x1; + else + corner.x = position2d.x; + + if (position2d.y < rectangle.y0) + corner.y = rectangle.y0; + else + if (position2d.y > rectangle.y1) + corner.y = rectangle.y1; + else + corner.y = position2d.y; + + return position2d.magnitudeBetweenSquared (corner); + } + else + { + const Vector & vmin = getBoxExtent ().getMin (); + const Vector & vmax = getBoxExtent ().getMax (); + + if (vmin.x <= position.x && vmax.x >= position.x && + vmin.z <= position.z && vmax.z >= position.z && + (!isBoxExtentInitialized () || + (vmin.y <= position.y && vmax.y >= position.y))) + return 0.f; + + Vector corner; + + // decide which octant the vector is in, and find the distance appropriately + + if (position.z < vmin.z) + corner.z = vmin.z; + else + if (position.z > vmax.z) + corner.z = vmax.z; + else + corner.z = position.z; + + // uninitialized box extent has a invalid y values, so just use the min value. + if (position.y < vmin.y || !isBoxExtentInitialized ()) + corner.y = vmin.y; + else + if (position.y > vmax.y) + corner.y = vmax.y; + else + corner.y = position.y; + + + if (position.x < vmin.x) + corner.x = vmin.x; + else + if (position.x > vmax.x) + corner.x = vmax.x; + else + corner.x = position.x; + + return position.magnitudeBetweenSquared (corner); + } +} + +//----------------------------------------------------------------- + +const TerrainQuadTree::Node * TerrainQuadTree::Node::getNeighbor (const int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 4); + return m_neighbors [index]; +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Node * TerrainQuadTree::Node::getNeighbor (const int index) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 4); + return m_neighbors [index]; +} //lint !e1762 //-- function could be made const (this is the non-const version) + +// ====================================================================== +// PUBLIC TerrainQuadTree +// ====================================================================== + +void TerrainQuadTree::setUseDistance2d (bool useDistance2d) +{ + ms_useDistance2d = useDistance2d; +} + +//----------------------------------------------------------------- +/** +* Construct a tree centered at 0,0 with the root node having the specified size. +*/ +TerrainQuadTree::TerrainQuadTree (const int maxsize, const float minChunkWidthInMeters) : + m_nodes (0) +{ + //-- is there more than one of these?!? -ALS + Node::install (); + + REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportLogPrint (), ("TerrainQuadTree creating at position %d,%d, size=%d\n", -maxsize/2, -maxsize/2, maxsize)); + m_nodes = new Node (-maxsize/2, -maxsize/2, maxsize, minChunkWidthInMeters); +}; + +//----------------------------------------------------------------- + +TerrainQuadTree::~TerrainQuadTree () +{ + IGNORE_RETURN (m_nodes->removeSubNodes (true)); + delete m_nodes; + m_nodes = 0; + + Node::remove (); +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Iterator TerrainQuadTree::getIterator () const +{ + return Iterator (m_nodes); +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Node * TerrainQuadTree::addChunk (ProceduralTerrainAppearance::Chunk * const chunk, const int size) +{ + return m_nodes->addChunk (chunk, size); +} + +//----------------------------------------------------------------- + +void TerrainQuadTree::removeChunk (ProceduralTerrainAppearance::Chunk * const chunk, bool deleteChunk) +{ + m_nodes->removeChunk (chunk, deleteChunk); +} + +//----------------------------------------------------------------- + +int TerrainQuadTree::getNumberOfChunks () const +{ + NOT_NULL (m_nodes); + return m_nodes->getNumberOfChunks (); +} + +//----------------------------------------------------------------- + +void TerrainQuadTree::pruneTree () +{ + NOT_NULL (m_nodes); + m_nodes->pruneTree (); +} + +//----------------------------------------------------------------- + +ProceduralTerrainAppearance::Chunk * TerrainQuadTree::findChunk (const int x, const int z, const int size) const +{ + NOT_NULL (m_nodes); + Node * const node = m_nodes->findChunkNode (0, x, z, size); + return node ? node->getChunk () : 0; +} + +//----------------------------------------------------------------- + +TerrainQuadTree::Node * TerrainQuadTree::findChunkNode (const int x, const int z, const int size) const +{ + NOT_NULL (m_nodes); + return m_nodes->findChunkNode (0, x, z, size); +} + +//----------------------------------------------------------------- + +bool TerrainQuadTree::hasChunk (const int x, const int z, const int size) const +{ + NOT_NULL (m_nodes); + return m_nodes->hasChunk (0, x, z, size); +} + +//----------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.h b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.h new file mode 100644 index 00000000..cb92dce0 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/appearance/TerrainQuadTree.h @@ -0,0 +1,741 @@ +// ====================================================================== +// +// TerrainQuadTree.h +// copyright 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_TerrainQuadTree_H +#define INCLUDED_TerrainQuadTree_H + +// ====================================================================== + +#include "sharedCollision/BoxExtent.h" +#include "sharedFoundation/MemoryBlockManagerMacros.h" +#include "sharedTerrain/ProceduralTerrainAppearance.h" + +// ====================================================================== +/** +* TerrainQuadTree is a wrapper class for a quadtree of TerrainQuadTree::Nodes +* +* @author jwatson +* @date 2001-01-12 +* @see nothing +*/ + +class TerrainQuadTree +{ +public: + + /** + * TerrainQuadTree::Node is a node in the Terrain Quad Tree. The interface is pretty fat. (not phat) + */ + + class Node + { + MEMORY_BLOCK_MANAGER_INTERFACE_WITHOUT_INSTALL; + + public: + + static void install (); + static void remove (); + + public: + + /** + * neighbors + */ + enum + { + NORTH = 0, + WEST = 1, + SOUTH = 2, + EAST = 3, + NUM_NEIGHBORS = 4 + }; + + /** + * neighbor flags + */ + enum + { + NORTH_FLAG = (1<<0) + ,WEST_FLAG = (1<<1) + ,SOUTH_FLAG = (1<<2) + ,EAST_FLAG = (1<<3) + }; + + static const int REVERSE_DIRECTIONS[4]; + + /** + * quadrants + */ + enum + { + NORTHEAST = 0, + NORTHWEST = 1, + SOUTHWEST = 2, + SOUTHEAST = 3 + + }; + + static const int OPPOSITE_QUADRANTS[4]; + + /** + * half-quadrants + */ + enum + { + ENE = 0, + NNE = 1, + NNW = 2, + WNW = 3, + WSW = 4, + SSW = 5, + SSE = 6, + ESE = 7 + }; + + static const int OPPOSITE_HALFQUADRANTS[8]; + + /** + * MAX_SIZE should be the square root of the maximum numeric capacity of 32 bit unsigned int + */ + enum + { + MAX_SIZE = 1 << 14 + }; + + public: + + Node (int newX, int newZ, int newSize, float theMinChunkWidthInMeters); + ~Node (); + + void destroyNode (Node * node); + void removeNode (Node * node); + + void addNode (Node * node, int quadrant); + Node * addChunk (ProceduralTerrainAppearance::Chunk * newChunk, const int chunkSize); + + int removeSubNodes (bool deleteChunks); + int removeSubNodeChunks (bool deleteChunks, bool recurse=true); + + Node * findChunkNode (const ProceduralTerrainAppearance::Chunk * aChunk, int ax, int az, int chunkSize); + + const BoxExtent & getBoxExtent () const; + bool isBoxExtentInitialized () const; + + bool hasChunk (const ProceduralTerrainAppearance::Chunk * aChunk, int ax, int az, int chunkSize); + + bool nodeEncloses (int ax, int az) const; + + void pruneTree (); + void removeChunk (ProceduralTerrainAppearance::Chunk * aChunk, bool deleteChunk); + + const ProceduralTerrainAppearance::Chunk * getChunk () const; + ProceduralTerrainAppearance::Chunk * getChunk (); + + int32 getX () const; + int32 getZ () const; + int32 getSize () const; + + int getNumberOfChunks () const; + + unsigned getChildIndex () const; + Node * getParent (); + const Node * getParent () const; + Node * getSubNode (const int which) const; + + int getQuadrant (const int ax, const int az) const; + int getQuadrant (const Vector & v) const; + int getHalfQuadrant (const int ax, const int az) const; + int getHalfQuadrant (const Vector & v) const; + + float getDistanceSquared (const Vector & v) const; + + Node * findNode (int ax, int az, int asize); + + const Node * findFirstRenderableNode (const Vector& position) const; + Node * findFirstRenderableNode (const Vector& position); + + const Node * findFirstRenderableNode (int ax, int az) const; + Node * findFirstRenderableNode (int ax, int az); + + Node * findFirstRenderableLowerNeighbor (const Node * otherNode, int dir); + Node * findFirstRenderablePeerNeighbor (const Node * otherNode, int dir); + + bool isSelectedForRender () const; + void setSelectedForRender (bool b); + + //-- larger neighbor stuff + + bool getHasLargerNeighbor (int dir) const; + void setHasLargerNeighbor (int dir, bool b); + void clearHasLargerNeighbors (); + bool getHasAnyLargerNeighbors () const; + unsigned getHasLargerNeighbors () const; + + bool isOutsideBuildRange () const; + void setOutsideBuildRange (bool b); + + const Node * getNeighbor (int index) const; + Node * getNeighbor (int index); + + private: + + Node (); + Node (const Node &); + Node & operator= (const Node &); + + int internalRemoveSubNodes (bool deleteChunks); + int internalRemoveSubNodeChunks (bool deleteChunks, bool recurse) const; + + /** + * find the quadrant given the x and z coordinates relative + * to the center of this node + */ + template int getQuadrantTemplate (const T ax, const T az) const + { + // left quadrants + if (ax < 0) + { + // bottom left quadrant + if (az < 0) + return SOUTHWEST; + // top left quadrant + else + return NORTHWEST; + } + // bottom right quadrant + else if (az < 0) + return SOUTHEAST; + // top right quadrant + else + return NORTHEAST; + } + + /** + * find the half-quadrant given the x and z coordinates relative + * to the center of this node + */ + template int getHalfQuadrantTemplate (const T ax, const T az) const + { + // left quadrants + if (ax < 0) + { + // bottom left quadrant + if (az < 0) + { + return (ax < az) ? WSW : SSW; + } + // top left quadrant + else + { + return (-ax > az) ? NNW : WNW; + } + } + // bottom right quadrant + else if (az < 0) + { + return (ax < -az) ? SSE : ESE; + } + // top right quadrant + else + { + return (ax > az) ? ENE : NNE; + } + } + + private: + + /** + * The chunkspace coordinates of the node. + */ + const short m_x; + const short m_z; + + /** + * The chunkspace size (width & height) of this node. Size is always a power of 2. + * The maximum number of chunks contained under a node is size*size. + */ + const short m_size; + + unsigned short m_childIndex : 2; // The index of this child node as a subnode of its parent. + unsigned short m_worldExtentInitialized : 1; + unsigned short hasLargerNeighborFlags : 4; + unsigned short m_selectedForRender : 1; + unsigned short m_outsideBuildRange : 1; + + /** + * This is the width of the smallest chunk on the map. REDUNDANT, store elsewhere? + */ + const float m_minChunkWidthInMeters; + + /** + * The chunk which lives at this node. Currently all chunks are assumed + * to live on size 1 leaf nodes. + */ + ProceduralTerrainAppearance::Chunk * m_chunk; + + /** + * Subnodes are arranged spatially the same as mathematical quadrants. + */ + + Node * m_subNodes[4]; + Node * m_parent; + Node * m_neighbors[4]; + + /** + * Current number of size 1 chunks contained beneath this node. + */ + int m_numberOfChunks; + + /** + * The worldspace extents of this node. This extent contains all subnodes. + */ + BoxExtent m_worldExtent; + }; + + /** + * Constants for Iterator tree traversal + */ + + class IteratorConstants + { + public: + static const int ORDER_PRE[4]; + + // traversal starting with the specified corner, front to back + static const int ORDER_ENE[4]; + static const int ORDER_NNE[4]; + static const int ORDER_NNW[4]; + static const int ORDER_WNW[4]; + static const int ORDER_WSW[4]; + static const int ORDER_SSW[4]; + static const int ORDER_SSE[4]; + static const int ORDER_ESE[4]; + + static const int * const HALF_QUADRANT_ORDERS[8]; + }; + + /** + * TerrainQuadTree::Iterator is a preorder iterator + * To use an iterator, loop while the current node is non-null. If the + * current node's subtree should be processed further, call descend () + * on the iterator, otherwise call advance () to go to the next node. + * Either advance () or descend () should be called every loop iteration, + * otherwise an infinite loop will result. + * + * + * This template floatly depends on having a pointer type as its template parameter. + * T must be assignable from zero and have a default constructor. A zero sentinel + * is used to improve performance. + */ + + template + class IteratorTemplate + { + public: + + explicit IteratorTemplate (T node); + + void reset (T node); + + T advance (); + + bool isEmpty () const; + + T getCurNode (); + + T descend (const int * theOrder = IteratorConstants::ORDER_PRE); + + T descendOneChild (int index); + + void push (T node); + + + private: + + IteratorTemplate (); + + enum + { + maxDepth = 64 // 16 deep x 4 nodes + }; + + //* The iterator is a stack of nodes + T s[maxDepth]; + int depth; + }; + + /** + * The ordinary, non-const Iterator + */ + typedef IteratorTemplate Iterator; + + /** + * The const Iterator + */ + + typedef IteratorTemplate ConstIterator; + +public: + + static void setUseDistance2d (bool useDistance2d); + +public: + + explicit TerrainQuadTree (int maxsize, float theMinChunkWidthInMeters); + ~TerrainQuadTree (); + + Node * getTopNode (); + const Node * getTopNode () const; + + Iterator getIterator () const; + Node * addChunk (ProceduralTerrainAppearance::Chunk * chunk, const int chunkSize); + void removeChunk (ProceduralTerrainAppearance::Chunk * chunk, bool deleteChunk); + int getNumberOfChunks () const; + void pruneTree (); + + ProceduralTerrainAppearance::Chunk * findChunk (int ax, int az, int chunkSize) const; + Node * findChunkNode (int ax, int az, int chunkSize) const; + bool hasChunk (int ax, int az, int chunkSize) const; + +private: + + Node * m_nodes; + +private: + + TerrainQuadTree (); + TerrainQuadTree (const TerrainQuadTree&); + TerrainQuadTree& operator= (const TerrainQuadTree&); +}; + +//----------------------------------------------------------------- +// TerrainQuadTree::Node +//----------------------------------------------------------------- +/** +* Get the BoxExtent which contains this node. This is the enclosing BoxExtent +* of all chunks which are children of this node and its subnodes. +* @return the BoxExtent +*/ +inline const BoxExtent & TerrainQuadTree::Node::getBoxExtent () const +{ + return m_worldExtent; +} + +//----------------------------------------------------------------- +/** +* Have any float-world chunks ever been added to this Node or its' subnodes? +* If not, then the BoxExtent is not yet valid. +*/ + +inline bool TerrainQuadTree::Node::isBoxExtentInitialized () const +{ + return m_worldExtentInitialized; +} + +//----------------------------------------------------------------- +/** +* Get the chunk located at this node. Currently chunks are only found on size 1 leaf nodes. +*/ +inline const ProceduralTerrainAppearance::Chunk * TerrainQuadTree::Node::getChunk () const +{ + return m_chunk; +} + +//----------------------------------------------------------------- + +inline ProceduralTerrainAppearance::Chunk * TerrainQuadTree::Node::getChunk () +{ + return m_chunk; +} + +//----------------------------------------------------------------- +/** +* Get the X position of this node in chunkspace. +*/ +inline int32 TerrainQuadTree::Node::getX () const +{ + return m_x; +} + +//----------------------------------------------------------------- +/** +* Get the z position of this node in chunkspace. +*/ +inline int32 TerrainQuadTree::Node::getZ () const +{ + return m_z; +} + +//----------------------------------------------------------------- +/** +* Get the size of this node in chunkspace. +*/ +inline int32 TerrainQuadTree::Node::getSize () const +{ + return m_size; +} + +//----------------------------------------------------------------- +/** +* Get the number of chunks contained within this entire subtree. +*/ +inline int TerrainQuadTree::Node::getNumberOfChunks () const +{ + return m_numberOfChunks; +} + +//----------------------------------------------------------------- +/** +* Get the childIndex, or the quadrant of this node as related to it's parent node. +*/ +inline unsigned TerrainQuadTree::Node::getChildIndex () const +{ + return m_childIndex; +} + +//----------------------------------------------------------------- +/** +* Get the parent node. +*/ +inline TerrainQuadTree::Node * TerrainQuadTree::Node::getParent () +{ + return m_parent; +} + +//----------------------------------------------------------------- +/** +* Get the parent node +*/ +inline const TerrainQuadTree::Node * TerrainQuadTree::Node::getParent () const +{ + return m_parent; +} + +//----------------------------------------------------------------- +/** +* Get the child node in the specified quadrant of this node. +*/ +inline TerrainQuadTree::Node * TerrainQuadTree::Node::getSubNode (const int childIndex) const +{ + return m_subNodes [childIndex]; +} + +//----------------------------------------------------------------- +/** +* Is this node selected for rendering? If so, then it is rendered, and collision detection occurs with it. +*/ +inline bool TerrainQuadTree::Node::isSelectedForRender () const +{ + return m_selectedForRender; +} + +//----------------------------------------------------------------- + +inline void TerrainQuadTree::Node::setSelectedForRender (const bool selectedForRender) +{ + m_selectedForRender = selectedForRender; +} + +//----------------------------------------------------------------- +/** +* Has this node been flagged as having a larger neighbor in the specified direction? +*/ +inline bool TerrainQuadTree::Node::getHasLargerNeighbor (const int direction) const +{ + return 0!=(hasLargerNeighborFlags & (1< +inline TerrainQuadTree::IteratorTemplate::IteratorTemplate (T node) +{ + NOT_NULL (node); + + s[0] = 0; + s[1] = node; + depth = 1; +} +//----------------------------------------------------------------- +/** +* Reset the iterator. The sentinel should be already correct. +*/ + +template +inline void TerrainQuadTree::IteratorTemplate::reset (T node) +{ + NOT_NULL (node); + DEBUG_FATAL (s[0] != 0, ("Corrupt sentinel")); // verify the sentinel + s[1] = node; + depth = 1; +} + +//----------------------------------------------------------------- + +template +inline void TerrainQuadTree::IteratorTemplate::push (T node) +{ + NOT_NULL (node); + DEBUG_FATAL (depth >= maxDepth, ("TerrainQuadTree::IteratorTemplate: max depth exceeded")); + + s[++depth] = node; +} + +//----------------------------------------------------------------- +/** +* advance pops the current node off the stack and returns a pointer to +* the next one, if there is one. +*/ +template +inline T TerrainQuadTree::IteratorTemplate::advance () +{ + DEBUG_FATAL (depth <= 0, ("TerrainQuadTree::IteratorTemplate: advancing past root")); + + return s[--depth]; +} +//----------------------------------------------------------------- + +template +inline bool TerrainQuadTree::IteratorTemplate::isEmpty () const +{ + return depth==0; +} + +//----------------------------------------------------------------- +/** +* get the top node of the stack +*/ +template +inline T TerrainQuadTree::IteratorTemplate::getCurNode () +{ + return s[depth]; +} + +//----------------------------------------------------------------- +/** +* descend pushes the children of the current node onto the stack, +* in the reverse of the order specified. The result is that +* multiple calls to advance () will return the nodes in the order +* specified. The current node is removed from the stack, and the +* resulting top of the stack is returned. +*/ +template +inline T TerrainQuadTree::IteratorTemplate::descend (const int * theOrder) +{ + DEBUG_FATAL (isEmpty (), ("descent into empty iterator")); + + T node = s[depth--]; + + // go through the order backwards since our iterator uses a stack rather than a queue + for (int i = 3; i >= 0; --i) + { + const int index = theOrder [i]; + + if (node->getSubNode (index)) + push (node->getSubNode (index)); + } + + return s[depth]; +} + +//----------------------------------------------------------------- + +template +inline T TerrainQuadTree::IteratorTemplate::descendOneChild (const int index) +{ + DEBUG_FATAL (isEmpty (), ("descent into empty iterator")); + + T node = s[depth--]; + + if (node->getSubNode (index)) + push (node->getSubNode (index)); + + return getCurNode (); +} + +//----------------------------------------------------------------- +// TerrainQuadTree +//----------------------------------------------------------------- + +inline TerrainQuadTree::Node * TerrainQuadTree::getTopNode () +{ + return m_nodes; +} + +//----------------------------------------------------------------- + +inline const TerrainQuadTree::Node * TerrainQuadTree::getTopNode () const +{ + return m_nodes; +} + +//----------------------------------------------------------------- + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.cpp b/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.cpp new file mode 100644 index 00000000..1f2bdc18 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.cpp @@ -0,0 +1,88 @@ +//=================================================================== +// +// ConfigSharedTerrain.cpp +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ConfigSharedTerrain.h" + +#include "sharedFoundation/ConfigFile.h" + +//=================================================================== + +namespace +{ + int ms_maximumNumberOfChunksAllowed; + bool ms_disableGetHeight; + bool ms_debugReportInstall; + bool ms_debugReportLogPrint; + bool ms_disableFloraCaching; + float ms_maximumValidHeightInMeters; +} + +//=================================================================== + +int ConfigSharedTerrain::getMaximumNumberOfChunksAllowed () +{ + return ms_maximumNumberOfChunksAllowed; +} + +//------------------------------------------------------------------- + +bool ConfigSharedTerrain::getDisableGetHeight () +{ + return ms_disableGetHeight; +} + +//------------------------------------------------------------------- + +bool ConfigSharedTerrain::getDebugReportInstall () +{ + return ms_debugReportInstall; +} + +//------------------------------------------------------------------- + +bool ConfigSharedTerrain::getDebugReportLogPrint () +{ + return ms_debugReportLogPrint; +} + +//------------------------------------------------------------------- + +bool ConfigSharedTerrain::getDisableFloraCaching () +{ + return ms_disableFloraCaching; +} + +//------------------------------------------------------------------- + +float ConfigSharedTerrain::getMaximumValidHeightInMeters () +{ + return ms_maximumValidHeightInMeters; +} + +//=================================================================== + +#define KEY_BOOL(a,b) (ms_ ## a = ConfigFile::getKeyBool ("SharedTerrain", #a, b)) +#define KEY_INT(a,b) (ms_ ## a = ConfigFile::getKeyInt ("SharedTerrain", #a, b)) +#define KEY_FLOAT(a,b) (ms_ ## a = ConfigFile::getKeyFloat ("SharedTerrain", #a, b)) +//#define KEY_STRING (a,b) (ms_ ## a = ConfigFile::getKeyString ("SharedTerrain", #a, b)) + +//=================================================================== + +void ConfigSharedTerrain::install () +{ + KEY_INT (maximumNumberOfChunksAllowed, 40 * 1024); + KEY_BOOL (disableGetHeight, false); + KEY_BOOL (debugReportInstall, false); + KEY_BOOL (debugReportLogPrint, false); + KEY_BOOL (disableFloraCaching, false); + KEY_FLOAT (maximumValidHeightInMeters, 16000.0f); + + DEBUG_REPORT_LOG_PRINT (ms_debugReportInstall, ("ConfigSharedTerrain::install\n")); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.h b/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.h new file mode 100644 index 00000000..4f6d8f89 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/ConfigSharedTerrain.h @@ -0,0 +1,36 @@ +//=================================================================== +// +// ConfigSharedTerrain.h +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_ConfigSharedTerrain_H +#define INCLUDED_ConfigSharedTerrain_H + +//=================================================================== + +class ConfigSharedTerrain +{ +public: + + static void install (); + + static int getMaximumNumberOfChunksAllowed (); + static bool getDisableGetHeight (); + static bool getDebugReportInstall (); + static bool getDebugReportLogPrint (); + static bool getDisableFloraCaching (); + + static float getMaximumValidHeightInMeters (); + +private: + + ConfigSharedTerrain (); + ConfigSharedTerrain (const ConfigSharedTerrain&); + ConfigSharedTerrain& operator= (const ConfigSharedTerrain&); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/core/FirstSharedTerrain.h b/engine/shared/library/sharedTerrain/src/shared/core/FirstSharedTerrain.h new file mode 100644 index 00000000..891c6e89 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/FirstSharedTerrain.h @@ -0,0 +1,18 @@ +// ====================================================================== +// +// FirstTerrain.h +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#ifndef INCLUDED_FirstTerrain_H +#define INCLUDED_FirstTerrain_H + +// ====================================================================== + +#include "sharedFoundation/FirstSharedFoundation.h" + +// ====================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.cpp b/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.cpp new file mode 100644 index 00000000..c118f6c0 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.cpp @@ -0,0 +1,93 @@ +//=================================================================== +// +// SetupSharedTerrain.cpp +// asommers 9-10-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/SetupSharedTerrain.h" + +#include "sharedDebug/InstallTimer.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedFractal/MultiFractal.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "sharedTerrain/ServerProceduralTerrainAppearance.h" +#include "sharedTerrain/ServerProceduralTerrainAppearanceTemplate.h" +#include "sharedTerrain/ServerSpaceTerrainAppearanceTemplate.h" +#include "sharedTerrain/TerrainObject.h" +#include "sharedTerrain/WaterTypeManager.h" + +//=================================================================== + +namespace +{ + bool ms_installed; +} + +//=================================================================== + +SetupSharedTerrain::Data::Data () : + m_allowInactiveLayerItems (false) +{ +} + +//=================================================================== + +void SetupSharedTerrain::install (const SetupSharedTerrain::Data& /*data*/) +{ + InstallTimer const installTimer("SetupSharedTerrain::install"); + + DEBUG_FATAL (ms_installed, ("SetupSharedTerrain::install already installed")); + ms_installed = true; + + DEBUG_REPORT_LOG_PRINT (ConfigSharedTerrain::getDebugReportInstall (), ("SetupSharedTerrain::install\n")); + + ConfigSharedTerrain::install (); + + TerrainObject::install (); + ProceduralTerrainAppearance::install (); + ServerProceduralTerrainAppearanceTemplate::install (); + ServerSpaceTerrainAppearanceTemplate::install(); + WaterTypeManager::install(); + + ExitChain::add (SetupSharedTerrain::remove, "SetupSharedTerrain"); +} + +//------------------------------------------------------------------- + +void SetupSharedTerrain::remove () +{ + DEBUG_FATAL (!ms_installed, ("SetupSharedTerrain::remove not installed")); + ms_installed = false; +/* +#ifdef _DEBUG + MultiFractal::debugDump (); +#endif +*/ +} + +//------------------------------------------------------------------- + +bool SetupSharedTerrain::isInstalled () +{ + return ms_installed; +} + +//------------------------------------------------------------------- + +void SetupSharedTerrain::setupGameData (Data& data) +{ + data.m_allowInactiveLayerItems = false; +} + +//------------------------------------------------------------------- + +void SetupSharedTerrain::setupToolData (Data& data) +{ + data.m_allowInactiveLayerItems = true; +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.h b/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.h new file mode 100644 index 00000000..b9a98476 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/SetupSharedTerrain.h @@ -0,0 +1,53 @@ +//=================================================================== +// +// SetupSharedTerrain.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_SetupSharedTerrain_H +#define INCLUDED_SetupSharedTerrain_H + +//=================================================================== + +class SetupSharedTerrain +{ +public: + + class Data + { + public: + + Data (); + + private: + + bool m_allowInactiveLayerItems; + + private: + + friend class SetupSharedTerrain; + }; + +public: + + static void install (const Data& data); + static void remove (); + + static bool isInstalled (); + + static void setupGameData (Data& data); + static void setupToolData (Data& data); + +private: + + SetupSharedTerrain (); + SetupSharedTerrain (const SetupSharedTerrain&); + SetupSharedTerrain& operator= (const SetupSharedTerrain&); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.cpp b/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.cpp new file mode 100644 index 00000000..65b5b1d0 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.cpp @@ -0,0 +1,248 @@ +// ====================================================================== +// +// WaterTypeManager.cpp +// +// copyright 2005, Sony Online Entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/WaterTypeManager.h" + +#include "sharedDebug/InstallTimer.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedUtility/DataTable.h" +#include "sharedUtility/DataTableManager.h" + +#include + +// ====================================================================== + +bool WaterTypeManager::ms_installed = false; +WaterTypeManager::WaterTypeDataType * WaterTypeManager::ms_waterTypeData=NULL; +WaterTypeManager::CreatureWaterTypeDataType* WaterTypeManager::ms_creatureWaterTypeData=NULL; + +// ====================================================================== + +WaterTypeManager::WaterTypeDataRecord::WaterTypeDataRecord() : +m_typeId(0), +m_name(), +m_causesDamage(false), +m_damageKills(false), +m_damageInterval(0), +m_damagePerInterval(0), +m_transparent(false) +{ +} + +// ====================================================================== + +WaterTypeManager::CreatureWaterTypeDataRecord::CreatureWaterTypeDataRecord() : +m_objectTemplateName(), +m_lavaResistance(0.0f) +{ +} + +// ====================================================================== + +void WaterTypeManager::install() +{ + InstallTimer const installTimer("WaterTypeManager::install"); + + DEBUG_FATAL(ms_installed,("WaterTypeManager::install was called more than once.")); + ms_waterTypeData = new WaterTypeDataType; + ms_creatureWaterTypeData = new CreatureWaterTypeDataType; + ms_installed = true; + + ExitChain::add(&remove,"WaterTypeManager::remove"); + + { + DataTable const * const waterTypeDataTable = DataTableManager::getTable("datatables/terrain/water_values.iff", true); + FATAL(!waterTypeDataTable,("water_values data table could not be opened.")); + int const numRows = waterTypeDataTable->getNumRows(); + for (int row=0; rowgetStringValue("water_type",row); + data.m_causesDamage = (waterTypeDataTable->getIntValue("causes_damage",row) != 0); + data.m_damageKills = (waterTypeDataTable->getIntValue("damage_kills",row) != 0); + data.m_damageInterval = waterTypeDataTable->getIntValue("damage_interval_secs", row); + data.m_damagePerInterval = waterTypeDataTable->getFloatValue("damage_per_interval_percentage",row); + data.m_transparent = (waterTypeDataTable->getIntValue("transparent",row) != 0); + (*ms_waterTypeData)[data.m_typeId] = data; + } + DataTableManager::close("datatables/terrain/water_values.iff"); + } + + { + DataTable const* const creatureWaterTypeDataTable = DataTableManager::getTable("datatables/terrain/creature_water_values.iff",true); + FATAL(!creatureWaterTypeDataTable,("creature_water_values data table could not be opened.")); + int const numRows = creatureWaterTypeDataTable->getNumRows(); + for(int row=0; row < numRows; ++row) + { + CreatureWaterTypeDataRecord data; + + data.m_objectTemplateName = creatureWaterTypeDataTable->getStringValue("object_template_name",row); + data.m_lavaResistance = creatureWaterTypeDataTable->getFloatValue("lava_resistance",row); + if(data.m_lavaResistance > 100.0f) + { + data.m_lavaResistance = 100.0f; + } + else if(data.m_lavaResistance < 0.0f) + { + data.m_lavaResistance = 0.0f; + } + (*ms_creatureWaterTypeData)[data.m_objectTemplateName] = data; + } + DataTableManager::close("datatables/terrain/creature_water_values.iff"); + } +} + +// ---------------------------------------------------------------------- + +void WaterTypeManager::remove() +{ + DEBUG_FATAL(!ms_installed,("WaterTypeManager not installed")); + { + /* + // JU_TODO: temp - reference if we need to preload the character or vehicle effects here + for (WaterTypeManager::WaterTypeDataType::iterator it = ms_waterTypeData->begin(); it != ms_waterTypeData->end(); ++it) + { + WaterTypeDataRecord & waterTypeDataRecord = (*it).second; + waterTypeDataRecord.releaseResources(); + } + */ + } + + delete ms_waterTypeData; + ms_waterTypeData=NULL; + delete ms_creatureWaterTypeData; + ms_creatureWaterTypeData=NULL; + ms_installed = false; +} + +// ---------------------------------------------------------------------- + +bool WaterTypeManager::getCausesDamage(TerrainGeneratorWaterType type) +{ + bool ret = false; + + WaterTypeDataType::const_iterator const i = ms_waterTypeData->find(type); + if (i == ms_waterTypeData->end()) + { + WARNING(true,("WaterTypeManager::getCausesDamage: Received request with type id %i, which isn't in the data table.", type)); + } + else + { + WaterTypeDataRecord const & data = i->second; + ret = data.m_causesDamage; + } + + return ret; +} + +// ---------------------------------------------------------------------- + +bool WaterTypeManager::getDamageKills(TerrainGeneratorWaterType type) +{ + bool ret = false; + + WaterTypeDataType::const_iterator const i = ms_waterTypeData->find(type); + if (i == ms_waterTypeData->end()) + { + WARNING(true,("WaterTypeManager::getDamageKills: Received request with type id %i, which isn't in the data table.", type)); + } + else + { + WaterTypeDataRecord const & data = i->second; + ret = data.m_damageKills; + } + + return ret; +} + +// ---------------------------------------------------------------------- + +int WaterTypeManager::getDamageInterval(TerrainGeneratorWaterType type) +{ + int ret = 0; + + WaterTypeDataType::const_iterator const i = ms_waterTypeData->find(type); + if (i == ms_waterTypeData->end()) + { + WARNING(true,("WaterTypeManager::getDamageInterval: Received request with type id %i, which isn't in the data table.", type)); + } + else + { + WaterTypeDataRecord const & data = i->second; + ret = data.m_damageInterval; + } + + return ret; +} + +// ---------------------------------------------------------------------- + +float WaterTypeManager::getDamagePerInterval(TerrainGeneratorWaterType type) +{ + float ret = 0.0f; + + WaterTypeDataType::const_iterator const i = ms_waterTypeData->find(type); + if (i == ms_waterTypeData->end()) + { + WARNING(true,("WaterTypeManager::getDamagePerInterval: Received request with type id %i, which isn't in the data table.", type)); + } + else + { + WaterTypeDataRecord const & data = i->second; + ret = data.m_damagePerInterval; + } + + return ret; +} + +// ---------------------------------------------------------------------- + +bool WaterTypeManager::getTransparent(TerrainGeneratorWaterType type) +{ + bool ret = false; + + WaterTypeDataType::const_iterator const i = ms_waterTypeData->find(type); + if (i == ms_waterTypeData->end()) + { + WARNING(true,("WaterTypeManager::getTransparent: Received request with type id %i, which isn't in the data table.", type)); + } + else + { + WaterTypeDataRecord const & data = i->second; + ret = data.m_transparent; + } + + return ret; + +} + +// ---------------------------------------------------------------------- + +float WaterTypeManager::getLavaResistance(const std::string& objectTemplateName) +{ + float ret = 0.0f; + CreatureWaterTypeDataType::const_iterator const i = ms_creatureWaterTypeData->find(objectTemplateName); + if(i != ms_creatureWaterTypeData->end()) + { + CreatureWaterTypeDataRecord const &data = i->second; + ret = data.m_lavaResistance; + } + + return ret; +} + +// ====================================================================== + + + + + + + diff --git a/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.h b/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.h new file mode 100644 index 00000000..5fcf4a51 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/core/WaterTypeManager.h @@ -0,0 +1,71 @@ +//=================================================================== +// +// WaterTypeManager.h +// +// copyright 2005, Sony Online Entertainment +// +//=================================================================== + +#ifndef INCLUDED_WaterTypeManager_H +#define INCLUDED_WaterTypeManager_H + +#include +#include "sharedTerrain/TerrainGeneratorType.def" + + +//=================================================================== + +class WaterTypeManager +{ +public: + static void install (); + static void remove (); + +public: + static bool getCausesDamage(TerrainGeneratorWaterType type); + static bool getDamageKills(TerrainGeneratorWaterType type); + static int getDamageInterval(TerrainGeneratorWaterType type); + static float getDamagePerInterval(TerrainGeneratorWaterType type); + static bool getTransparent(TerrainGeneratorWaterType type); + static float getLavaResistance(const std::string& objectTemplateName); + +private: + struct WaterTypeDataRecord + { + + public: + WaterTypeDataRecord(); + + public: + int m_typeId; + std::string m_name; + bool m_causesDamage; + bool m_damageKills; + int m_damageInterval; + float m_damagePerInterval; + bool m_transparent; + }; + + struct CreatureWaterTypeDataRecord + { + public: + CreatureWaterTypeDataRecord(); + + public: + std::string m_objectTemplateName; + float m_lavaResistance; + + }; + + typedef stdmap::fwd WaterTypeDataType; + typedef stdmap::fwd CreatureWaterTypeDataType; + + static bool ms_installed; + static WaterTypeDataType * ms_waterTypeData; + static CreatureWaterTypeDataType* ms_creatureWaterTypeData; +}; + +//=================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.cpp b/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.cpp new file mode 100644 index 00000000..6cbe0abc --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.cpp @@ -0,0 +1,48 @@ +//=================================================================== +// +// FloraManager.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/FloraManager.h" + +//=================================================================== + +namespace FloraManagerNamespace +{ + const Object* ms_referenceObject; +} + +using namespace FloraManagerNamespace; + +//=================================================================== + +const Object* FloraManager::getReferenceObject () +{ + return ms_referenceObject; +} + +//------------------------------------------------------------------- + +void FloraManager::setReferenceObject (const Object* const referenceObject) +{ + ms_referenceObject = referenceObject; +} + +//=================================================================== + +FloraManager::FloraManager () +{ +} + +//------------------------------------------------------------------- + +FloraManager::~FloraManager () +{ +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.h b/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.h new file mode 100644 index 00000000..1a0569f1 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/flora/FloraManager.h @@ -0,0 +1,34 @@ +//=================================================================== +// +// FloraManager.h +// asommers +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_FloraManager_H +#define INCLUDED_FloraManager_H + +//=================================================================== + +class Object; + +//=================================================================== + +class FloraManager +{ +public: + + static const Object* getReferenceObject (); + static void setReferenceObject (const Object* referenceObject); + +public: + + FloraManager (); + virtual ~FloraManager ()=0; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.cpp b/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.cpp new file mode 100644 index 00000000..92d72722 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.cpp @@ -0,0 +1,25 @@ +//=================================================================== +// +// ServerFloraManager.cpp +// asommers +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ServerFloraManager.h" + +//=================================================================== + +ServerFloraManager::ServerFloraManager () +{ +} + +//------------------------------------------------------------------- + +ServerFloraManager::~ServerFloraManager () +{ +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.h b/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.h new file mode 100644 index 00000000..20bd42eb --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/flora/ServerFloraManager.h @@ -0,0 +1,26 @@ +//=================================================================== +// +// ServerFloraManager.h +// asommers +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_ServerFloraManager_H +#define INCLUDED_ServerFloraManager_H + +//=================================================================== + +class ServerFloraManager +{ +public: + + ServerFloraManager (); + virtual ~ServerFloraManager ()=0; +}; + +//=================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Affector.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/Affector.cpp new file mode 100644 index 00000000..f1f02454 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Affector.cpp @@ -0,0 +1,454 @@ +//=================================================================== +// +// Affector.cpp +// asommers 2001-01-17 +// +// copyright 2001, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/Affector.h" + +#include "sharedMath/Line2d.h" + +#include + +//=================================================================== + +namespace +{ + inline const float computeT (const Vector2d& start, const Vector2d& end, const Vector2d& point) + { + return ((point.x - start.x) * (end.x - start.x) + (point.y - start.y) * (end.y - start.y)) / (sqr (end.x - start.x) + sqr (end.y - start.y)); + } + + template + inline const T min (const T& a, const T& b) + { + return a < b ? a : b; + } +} + +//=================================================================== + +void AffectorBoundaryPoly::FindData::reset () +{ + height = 0.f; + distanceToCenter = 0.f; + t = 0.f; + length = 0.f; +} + +//=================================================================== + +bool AffectorBoundaryPoly::ms_enabled = true; + +//=================================================================== + +AffectorBoundaryPoly::AffectorBoundaryPoly (const Tag newTag, const TerrainGeneratorAffectorType newType) : + TerrainGenerator::Affector (newTag, newType), + m_featherFunction (TGFF_linear), + m_featherDistance (0.5f), + m_pointList (), + m_lengths (), + m_lengthTotals (), + m_width (4.f), + m_extent (), + m_heightData () +{ +} + +//------------------------------------------------------------------- + +AffectorBoundaryPoly::~AffectorBoundaryPoly () +{ +} + +//------------------------------------------------------------------- + +float AffectorBoundaryPoly::isWithin (const float worldX, const float worldZ) const +{ + if (!m_extent.isWithin (worldX, worldZ)) + return 0.f; + + const float widthSquared = sqr (m_width); + + float distanceSquared = widthSquared; + + //-- first, scan how far we are from the points + { + const int n = m_pointList.getNumberOfElements (); + int i; + for (i = 0; i < n; ++i) + { + const float x = m_pointList [i].x; + const float y = m_pointList [i].y; + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + } + + //-- next, scan each line + { + const int n = m_pointList.getNumberOfElements () - 1; + int i; + for (i = 0; i < n; ++i) + { + const float x1 = m_pointList [i].x; + const float y1 = m_pointList [i].y; //lint !e578 //-- hides y1 (double) + const float x2 = m_pointList [i + 1].x; + const float y2 = m_pointList [i + 1].y; + + const float u = ((worldX - x1) * (x2 - x1) + (worldZ - y1) * (y2 - y1)) / (sqr (x2 - x1) + sqr (y2 - y1)); + if (u >= 0 && u <= 1) + { + const float x = x1 + u * (x2 - x1); + const float y = y1 + u * (y2 - y1); + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + } + } + + if (distanceSquared < widthSquared) + { + const float newFeatherDistance = m_width * (1.f - getFeatherDistance ()); + const float newFeatherDistanceSquared = sqr (newFeatherDistance); + + if (distanceSquared < newFeatherDistanceSquared) + return 1.f; + + return 1.f - (sqrt (distanceSquared) - newFeatherDistance) / (m_width - newFeatherDistance); + } + + return 0.f; +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::addPoint (const Vector2d& point) +{ + m_pointList.add (point); + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::replacePoint (const int index, const Vector2d& newPoint) +{ + m_pointList [index] = newPoint; + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::removePoint (const int index) +{ + m_pointList.removeIndexAndCompactList (index); + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::clearPointList () +{ + m_pointList.clear (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::copyPointList (const ArrayList& newPointList) +{ + m_pointList = newPointList; + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::recalculate () +{ + // + // recalculate extent + // + { + m_extent.x0 = FLT_MAX; + m_extent.y0 = FLT_MAX; + m_extent.x1 = -FLT_MAX; + m_extent.y1 = -FLT_MAX; + + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); ++i) + m_extent.expand (m_pointList [i].x, m_pointList [i].y); + + m_extent.x0 -= m_width; + m_extent.y0 -= m_width; + m_extent.x1 += m_width; + m_extent.y1 += m_width; + } + + // + // recalculate lengths + // + { + m_lengths.clear (); + m_lengthTotals.clear (); + + m_lengths.push_back (0.f); + m_lengthTotals.push_back (0.f); + + int i; + for (i = 1; i < m_pointList.getNumberOfElements (); ++i) + { + m_lengths.push_back (m_pointList [i].magnitudeBetween (m_pointList [i - 1])); + m_lengthTotals.push_back (m_lengths [i] + m_lengthTotals [i - 1]); + } + } +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::rotate (const float angle) +{ + if (m_pointList.getNumberOfElements () == 0) + return; + + Vector2d center; + + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); i++) + center += m_pointList [i]; + + center.x /= static_cast (m_pointList.getNumberOfElements ()); + center.y /= static_cast (m_pointList.getNumberOfElements ()); + + rotate (angle, center); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::rotate (const float angle, const Vector2d& center) +{ + if (m_pointList.getNumberOfElements () == 0) + return; + + const float cosAngle = cos (angle); + const float sinAngle = sin (angle); + + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); i++) + { + Vector2d point; + point.x = m_pointList [i].x - center.x; + point.y = m_pointList [i].y - center.y; + + Vector2d newPoint; + newPoint.x = center.x + point.x * cosAngle - point.y * sinAngle; + newPoint.y = center.y + point.x * sinAngle + point.y * cosAngle; + + m_pointList [i] = newPoint; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::translate (const Vector2d& translation) +{ + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); i++) + m_pointList [i] += translation; + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::scale (const float scalar) +{ + if (m_pointList.getNumberOfElements () == 0) + return; + + Vector2d center; + + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); i++) + center += m_pointList [i]; + + center.x /= static_cast (m_pointList.getNumberOfElements ()); + center.y /= static_cast (m_pointList.getNumberOfElements ()); + + for (i = 0; i < m_pointList.getNumberOfElements (); i++) + { + m_pointList [i].x = (m_pointList [i].x - center.x) * scalar + center.x; + m_pointList [i].y = (m_pointList [i].y - center.y) * scalar + center.y; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::expand (Rectangle2d& parentExtent) const +{ + parentExtent.expand (m_extent.x0, m_extent.y0); + parentExtent.expand (m_extent.x1, m_extent.y1); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::setWidth (const float newWidth) +{ + m_width = newWidth; + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::setFeatherFunction (TerrainGeneratorFeatherFunction newFeatherFunction) +{ + m_featherFunction = newFeatherFunction; +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::setFeatherDistance (const float newFeatherDistance) +{ + m_featherDistance = newFeatherDistance; +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::enable () +{ + ms_enabled = true; +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::disable () +{ + ms_enabled = false; +} + +//------------------------------------------------------------------- + +bool AffectorBoundaryPoly::isEnabled () +{ + return ms_enabled; +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::clearHeightData () +{ + m_heightData.clear (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::addSegmentHeightData () +{ + m_heightData.addSegment (); +} + +//------------------------------------------------------------------- + +void AffectorBoundaryPoly::addPointHeightData (const Vector& point) +{ + m_heightData.addPoint (point); +} + +//------------------------------------------------------------------- + +bool AffectorBoundaryPoly::find (const Vector2d& point, const float width, FindData& result, bool ignoreHeight) const +{ + if (m_pointList.empty ()) + return false; + + const float widthSquared = sqr (width); + float distanceSquared = widthSquared; + + //-- first, scan how far we are from the points + { + int i; + for (i = 0; i < m_pointList.size (); ++i) + { + const float thisDistanceSquared = point.magnitudeBetweenSquared (m_pointList [i]); + if (thisDistanceSquared < distanceSquared) + { + distanceSquared = thisDistanceSquared; + result.t = m_lengthTotals [i]; + result.height = (i != m_pointList.size () - 1) ? m_heightData.getPoint (i, 0).y : m_heightData.getPoint (i - 1, m_heightData.getNumberOfPoints (i - 1) - 1).y; + } + } + } + + int segmentIndex = 0; + Vector2d resultPoint; + bool searchHeightData = false; + + //-- next, scan each line + { + int i; + for (i = 0; i < m_pointList.size () - 1; ++i) + { + const Vector2d start = m_pointList [i]; + const Vector2d end = m_pointList [i + 1]; + + const float t = computeT (start, end, point); + if (t >= 0 && t <= 1) + { + const Vector2d lerpedPoint = Vector2d::linearInterpolate (start, end, t); + const float thisDistanceSquared = point.magnitudeBetweenSquared (lerpedPoint); + if (thisDistanceSquared < distanceSquared) + { + distanceSquared = thisDistanceSquared; + segmentIndex = i; + resultPoint = lerpedPoint; + if(!ignoreHeight) // some affectors don't have height data (ribbon) + { + searchHeightData = true; + } + + result.t = m_lengthTotals [i] + (t * m_lengths [i + 1]); + } + } + } + } + + if (distanceSquared < widthSquared) + { + result.distanceToCenter = static_cast (sqrt (distanceSquared)); + result.length = m_lengthTotals.back (); + + if (searchHeightData && !m_heightData.find (segmentIndex, resultPoint, result.height)) + { + static bool s_warnedMissingHeightData = false; + + if (!s_warnedMissingHeightData) + { + s_warnedMissingHeightData = true; + DEBUG_WARNING (true, ("AffectorBoundaryPoly::find - couldn't find height data for %s. Did you not bake the river/road data?", getName ())); + } + + result.height = 0.f; + } + + return true; + } + + return false; +} + +//=================================================================== + + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Affector.h b/engine/shared/library/sharedTerrain/src/shared/generator/Affector.h new file mode 100644 index 00000000..6cb5ad26 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Affector.h @@ -0,0 +1,200 @@ +//=================================================================== +// +// Affector.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_Affector_H +#define INCLUDED_Affector_H + +//=================================================================== + +#include "sharedMath/Vector2d.h" +#include "sharedTerrain/TerrainGenerator.h" +#include "sharedTerrain/HeightData.h" + +//=================================================================== + +class AffectorExclude : public TerrainGenerator::Affector +{ +public: + + AffectorExclude (); + virtual ~AffectorExclude (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + +private: + + void load_0000 (Iff& iff); + +private: + + AffectorExclude (const AffectorExclude& rhs); + AffectorExclude& operator= (const AffectorExclude& rhs); +}; + +//=================================================================== + +class AffectorBoundaryPoly : public TerrainGenerator::Affector +{ +public: + + AffectorBoundaryPoly (Tag newTag, TerrainGeneratorAffectorType newType); + virtual ~AffectorBoundaryPoly ()=0; + + virtual float isWithin (float worldX, float worldZ) const; + TerrainGeneratorFeatherFunction getFeatherFunction () const; + void setFeatherFunction (TerrainGeneratorFeatherFunction newFeatherFunction); + float getFeatherDistance () const; + void setFeatherDistance (float newFeatherDistance); + + void rotate (float angle); + void rotate (float angle, const Vector2d& center); + void translate (const Vector2d& translation); + void scale (float scalar); + void expand (Rectangle2d& extent) const; + const Vector2d getCenter () const; + + const ArrayList& getPointList () const; + int getNumberOfPoints () const; + const Vector2d& getPoint (int index) const; + void addPoint (const Vector2d& point); + void replacePoint (int index, const Vector2d& point); + void removePoint (int index); + void clearPointList (); + void copyPointList (const ArrayList& newPointList); + + void setWidth (float newWidth); + float getWidth () const; + + const Rectangle2d& getExtent () const; + + const HeightData& getHeightData () const; + void clearHeightData (); + void addSegmentHeightData (); + void addPointHeightData (const Vector& point); + virtual void createHeightData ()=0; + + //-- + static bool isEnabled (); + static void enable (); + static void disable (); + +protected: + + struct FindData + { + public: + + float height; + float distanceToCenter; + float t; + float length; + + public: + + void reset (); + }; + +protected: + + virtual void recalculate (); + + //-- find the closest height along the list of points to position (returns t along entire list of segments) + bool find (const Vector2d& point, const float width, FindData& result,bool ignoreHeight = false) const; + +protected: + + TerrainGeneratorFeatherFunction m_featherFunction; + float m_featherDistance; + ArrayList m_pointList; + ArrayList m_lengths; + ArrayList m_lengthTotals; + float m_width; + Rectangle2d m_extent; + HeightData m_heightData; + +private: + + AffectorBoundaryPoly (const AffectorBoundaryPoly& rhs); + AffectorBoundaryPoly& operator= (const AffectorBoundaryPoly& rhs); + +private: + + static bool ms_enabled; +}; + +//=================================================================== + +inline const ArrayList& AffectorBoundaryPoly::getPointList () const +{ + return m_pointList; +} + +//------------------------------------------------------------------- + +inline int AffectorBoundaryPoly::getNumberOfPoints () const +{ + return m_pointList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const Vector2d& AffectorBoundaryPoly::getPoint (int index) const +{ + return m_pointList [index]; +} + +//------------------------------------------------------------------- + +inline const Vector2d AffectorBoundaryPoly::getCenter () const +{ + return m_extent.getCenter (); +} + +//------------------------------------------------------------------- + +inline float AffectorBoundaryPoly::getWidth () const +{ + return m_width; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorFeatherFunction AffectorBoundaryPoly::getFeatherFunction () const +{ + return m_featherFunction; +} + +//------------------------------------------------------------------- + +inline float AffectorBoundaryPoly::getFeatherDistance () const +{ + return m_featherDistance; +} + +//------------------------------------------------------------------- + +inline const Rectangle2d& AffectorBoundaryPoly::getExtent () const +{ + return m_extent; +} + +//------------------------------------------------------------------- + +inline const HeightData& AffectorBoundaryPoly::getHeightData () const +{ + return m_heightData; +} + +//=================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.cpp new file mode 100644 index 00000000..03b0a33b --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.cpp @@ -0,0 +1,616 @@ +// +// AffectorColor.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorColor.h" + +#include "sharedFile/Iff.h" +#include "sharedFractal/MultiFractal.h" +#include "sharedFractal/MultiFractalReaderWriter.h" +#include "sharedImage/Image.h" +#include "sharedImage/ImageFormatList.h" +#include "sharedTerrain/Affector.h" +#include "sharedSynchronization/Mutex.h" + +#include +#include + +//------------------------------------------------------------------- + +static const PackedRgb computeColor (const PackedRgb& oldColor, const PackedRgb& desiredColor, const TerrainGeneratorOperation operation, const float amount) +{ + PackedRgb newColor = desiredColor; + + if (amount < 1.f) + { + newColor.r = static_cast (desiredColor.r * amount); + newColor.g = static_cast (desiredColor.g * amount); + newColor.b = static_cast (desiredColor.b * amount); + } + + switch (operation) + { + case TGO_add: + { + newColor.r = static_cast (std::min (oldColor.r + newColor.r, 255)); + newColor.g = static_cast (std::min (oldColor.g + newColor.g, 255)); + newColor.b = static_cast (std::min (oldColor.b + newColor.b, 255)); + } + break; + + case TGO_subtract: + { + newColor.r = static_cast (std::max (oldColor.r - newColor.r, 0)); + newColor.g = static_cast (std::max (oldColor.g - newColor.g, 0)); + newColor.b = static_cast (std::max (oldColor.b - newColor.b, 0)); + } + break; + + case TGO_multiply: + { + newColor.r = static_cast (amount * (0.5f * desiredColor.r + 0.5f * oldColor.r) + (1.f - amount) * oldColor.r); + newColor.g = static_cast (amount * (0.5f * desiredColor.g + 0.5f * oldColor.g) + (1.f - amount) * oldColor.g); + newColor.b = static_cast (amount * (0.5f * desiredColor.b + 0.5f * oldColor.b) + (1.f - amount) * oldColor.b); + } + break; + + case TGO_replace: + default: + { + newColor.r = static_cast (amount * desiredColor.r + (1.f - amount) * oldColor.r); + newColor.g = static_cast (amount * desiredColor.g + (1.f - amount) * oldColor.g); + newColor.b = static_cast (amount * desiredColor.b + (1.f - amount) * oldColor.b); + } + break; + + case TGO_COUNT: + FATAL (true, ("invalid operation")); + break; + } + + return newColor; +} + +//------------------------------------------------------------------- +// +// AffectorColorConstant +// +AffectorColorConstant::AffectorColorConstant () : + TerrainGenerator::Affector (TAG_ACCN, TGAT_colorConstant), + operation (TGO_replace), + color () +{ +} + +//------------------------------------------------------------------- + +AffectorColorConstant::~AffectorColorConstant () +{ +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::setColor (const PackedRgb& newColor) +{ + color = newColor; +} + +//------------------------------------------------------------------- + +unsigned AffectorColorConstant::getAffectedMaps() const +{ + return TGM_color; +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + const PackedRgb oldColor = generatorChunkData.colorMap->getData (x, z); + const PackedRgb newColor = computeColor (oldColor, color, operation, amount); + + generatorChunkData.colorMap->setData (x, z, newColor); + } +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorColorConstant version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + operation = static_cast (newOperation); + + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorColorConstant::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (operation)); + iff.insertChunkData (color.r); + iff.insertChunkData (color.g); + iff.insertChunkData (color.b); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- +// +// AffectorColorRampHeight +// +AffectorColorRampHeight::AffectorColorRampHeight () : + TerrainGenerator::Affector (TAG_ACRH, TGAT_colorRampHeight), + image (0), + operation (TGO_replace), + lowHeight (0), + highHeight (0), + imageName (NON_NULL (new std::string)) +{ +} + +//------------------------------------------------------------------- + +AffectorColorRampHeight::~AffectorColorRampHeight () +{ + if (image) + { + delete image; + image = 0; + } + + delete imageName; + imageName = 0; +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::setLowHeight (const float newLowHeight) +{ + lowHeight = newLowHeight; +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::setHighHeight (const float newHighHeight) +{ + highHeight = newHighHeight; +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::setImage (const std::string& newImageName) +{ + *imageName = newImageName; + + if (image) + delete image; + + image = ImageFormatList::loadImage (imageName->c_str ()); + if (image) + { + DEBUG_WARNING (image->getHeight () != 1, ("height != 1")); + DEBUG_WARNING (! (image->getPixelFormat () == Image::PF_bgr_888 || image->getPixelFormat () == Image::PF_rgb_888), ("image is not in rgb or bgr format")); + } +} + +//------------------------------------------------------------------- + +static const PackedRgb getPixel (const Image* image, const int x, const int y) +{ + PackedRgb result = PackedRgb::solidBlack; + + if (x >= 0 && x < image->getWidth () && + y >= 0 && y < image->getHeight ()) + { + static Mutex mutex; + + mutex.enter (); + + const uint8* data = image->lockReadOnly (); + + data += y * image->getStride () + x * image->getBytesPerPixel (); + + if (image->getPixelFormat () == Image::PF_bgr_888) + { + result.b = *data++; + result.g = *data++; + result.r = *data++; + } + else + { + result.r = *data++; + result.g = *data++; + result.b = *data++; + } + + image->unlock (); + + mutex.leave (); + } + + return result; +} + +//------------------------------------------------------------------- + +unsigned AffectorColorRampHeight::getAffectedMaps() const +{ + return TGM_color; +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (image && amount > 0.f) + { + const float height = generatorChunkData.heightMap->getData (x, z); + if (WithinRangeInclusiveInclusive (lowHeight, height, highHeight)) + { + const PackedRgb oldColor = generatorChunkData.colorMap->getData (x, z); + const float t = (height - lowHeight) / (highHeight - lowHeight); + const PackedRgb color = getPixel (image, static_cast (t * (image->getWidth () - 1)), 0); + const PackedRgb newColor = computeColor (oldColor, color, operation, amount); + + generatorChunkData.colorMap->setData (x, z, newColor); + } + } +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorColorRampHeight version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + operation = static_cast (newOperation); + + lowHeight = iff.read_float (); + highHeight = iff.read_float (); + + char* newImageName = iff.read_string (); + setImage (newImageName); + delete [] newImageName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorColorRampHeight::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (operation)); + iff.insertChunkData (lowHeight); + iff.insertChunkData (highHeight); + iff.insertChunkString (imageName->c_str ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- +// +// AffectorColorRampFractal +// +AffectorColorRampFractal::AffectorColorRampFractal () : + TerrainGenerator::Affector (TAG_ACRF, TGAT_colorRampFractal), + m_multiFractal (0), + m_cachedFamilyId (-1), + image (0), + m_familyId (0), + operation (TGO_replace), + imageName (NON_NULL (new std::string)) +{ +} + +//------------------------------------------------------------------- + +AffectorColorRampFractal::~AffectorColorRampFractal () +{ + if (image) + { + delete image; + image = 0; + } + + delete imageName; + imageName = 0; + + m_multiFractal = 0; +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::setFamilyId (const int newFamilyId) +{ + m_familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::setImage (const std::string& newImageName) +{ + *imageName = newImageName; + + if (image) + delete image; + + image = ImageFormatList::loadImage (imageName->c_str ()); + if (image) + { + DEBUG_WARNING (image->getHeight () != 1, ("height != 1")); + DEBUG_WARNING (! (image->getPixelFormat () == Image::PF_bgr_888 || image->getPixelFormat () == Image::PF_rgb_888), ("image is not in rgb or bgr format")); + } +} + +//------------------------------------------------------------------- + +unsigned AffectorColorRampFractal::getAffectedMaps() const +{ + return TGM_color; +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (image && amount > 0.f) + { + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_multiFractal = generatorChunkData.fractalGroup->getFamilyMultiFractal (m_familyId); + } + + NOT_NULL (m_multiFractal); + + const PackedRgb oldColor = generatorChunkData.colorMap->getData (x, z); + const float t = m_multiFractal->getValueCache (worldX, worldZ, x, z); + const PackedRgb color = getPixel (image, static_cast (t * (image->getWidth () - 1)), 0); + const PackedRgb newColor = computeColor (oldColor, color, operation, amount); + + generatorChunkData.colorMap->setData (x, z, newColor); + } +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::load (Iff& iff, FractalGroup& fractalGroup) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff, fractalGroup); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorColorRampFractal version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::load_0000 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load the fractal settings + MultiFractal multiFractal; + MultiFractalReaderWriter::load (iff, multiFractal); + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + operation = static_cast (newOperation); + + char* newImageName = iff.read_string (); + setImage (newImageName); + delete [] newImageName; + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFamilyId (iff.read_int32 ()); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + setOperation (static_cast (newOperation)); + + char* newImageName = iff.read_string (); + setImage (newImageName); + delete [] newImageName; + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorColorRampFractal::save (Iff& iff) const +{ + iff.insertForm (TAG_0001); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + iff.insertChunk (TAG (P,A,R,M)); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (static_cast (getOperation ())); + iff.insertChunkString (getImageName ().c_str ()); + + iff.exitChunk (); + + iff.exitForm (); + + iff.exitForm (); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.h new file mode 100644 index 00000000..d2804c5e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorColor.h @@ -0,0 +1,213 @@ +//=================================================================== +// +// AffectorColor.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_AffectorColor_H +#define INCLUDED_AffectorColor_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +class Image; + +//=================================================================== + +class AffectorColorConstant : public TerrainGenerator::Affector +{ +private: + + //-- accessible + TerrainGeneratorOperation operation; + PackedRgb color; + +private: + + void load_0000 (Iff& iff); + +private: + + AffectorColorConstant (const AffectorColorConstant& rhs); + AffectorColorConstant& operator= (const AffectorColorConstant& rhs); + +public: + + AffectorColorConstant (); + virtual ~AffectorColorConstant (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + const PackedRgb& getColor () const; + void setColor (const PackedRgb& newColor); +}; + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorColorConstant::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline const PackedRgb& AffectorColorConstant::getColor () const +{ + return color; +} + +//------------------------------------------------------------------- + +class AffectorColorRampHeight : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + Image* image; + + //-- accessible + TerrainGeneratorOperation operation; + float lowHeight; + float highHeight; + std::string* imageName; + +private: + + void load_0000 (Iff& iff); + +private: + + AffectorColorRampHeight (const AffectorColorRampHeight& rhs); + AffectorColorRampHeight& operator= (const AffectorColorRampHeight& rhs); + +public: + + AffectorColorRampHeight (); + virtual ~AffectorColorRampHeight (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + float getLowHeight () const; + void setLowHeight (float newLowHeight); + + float getHighHeight () const; + void setHighHeight (float newHighHeight); + + const std::string& getImageName () const; + void setImage (const std::string& newImageName); +}; + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorColorRampHeight::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline float AffectorColorRampHeight::getLowHeight () const +{ + return lowHeight; +} + +//------------------------------------------------------------------- + +inline float AffectorColorRampHeight::getHighHeight () const +{ + return highHeight; +} + +//------------------------------------------------------------------- + +inline const std::string& AffectorColorRampHeight::getImageName () const +{ + return *imageName; +} + +//------------------------------------------------------------------- + +class AffectorColorRampFractal : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable const MultiFractal* m_multiFractal; + mutable int m_cachedFamilyId; + Image* image; + + //-- accessible + int m_familyId; + TerrainGeneratorOperation operation; + std::string* imageName; + +private: + + void load_0000 (Iff& iff, FractalGroup& fractalGroup); + void load_0001 (Iff& iff); + +private: + + AffectorColorRampFractal (const AffectorColorRampFractal& rhs); + AffectorColorRampFractal& operator= (const AffectorColorRampFractal& rhs); + +public: + + AffectorColorRampFractal (); + virtual ~AffectorColorRampFractal (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff, FractalGroup& fractalGroup); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + const std::string& getImageName () const; + void setImage (const std::string& newImageName); + + int getFamilyId () const; + void setFamilyId (int id); +}; + +//------------------------------------------------------------------- + +inline int AffectorColorRampFractal::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorColorRampFractal::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline const std::string& AffectorColorRampFractal::getImageName () const +{ + return *imageName; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.cpp new file mode 100644 index 00000000..38a398ac --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.cpp @@ -0,0 +1,161 @@ +//=================================================================== +// +// AffectorEnvironment.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorEnvironment.h" + +#include "sharedTerrain/Affector.h" +#include "sharedFile/Iff.h" + +//------------------------------------------------------------------- +// +// AffectorEnvironment +// +AffectorEnvironment::AffectorEnvironment () : + TerrainGenerator::Affector (TAG_AENV, TGAT_environment), + m_cachedFamilyId (-1), + m_cachedEgi (), + m_cachedFeatherClamp (0.f), + m_familyId (0), + m_useFeatherClampOverride (false), + m_featherClampOverride (1.f) +{ +} + +//------------------------------------------------------------------- + +AffectorEnvironment::~AffectorEnvironment () +{ +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::setFamilyId (const int familyId) +{ + m_familyId = familyId; +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::setUseFeatherClampOverride (const bool useFeatherClampOverride) +{ + m_useFeatherClampOverride = useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::setFeatherClampOverride (const float featherClampOverride) +{ + m_featherClampOverride = featherClampOverride; +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::prepare () +{ + m_cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +unsigned AffectorEnvironment::getAffectedMaps() const +{ + return TGM_environment; +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_cachedEgi = generatorChunkData.environmentGroup->chooseEnvironment (m_familyId); + m_cachedFeatherClamp = generatorChunkData.environmentGroup->getFamilyFeatherClamp (m_familyId); + } + + const float featherClamp = m_useFeatherClampOverride ? m_featherClampOverride : m_cachedFeatherClamp; + + if (amount >= featherClamp) + { + EnvironmentGroup::Info egi = m_cachedEgi; + generatorChunkData.environmentMap->setData (x, z, egi); + } + } +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorEnvironment version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFamilyId (iff.read_int32 ()); + setUseFeatherClampOverride (iff.read_int32 () != 0); + setFeatherClampOverride (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorEnvironment::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (getUseFeatherClampOverride () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getFeatherClampOverride ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.h new file mode 100644 index 00000000..c20fdb40 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorEnvironment.h @@ -0,0 +1,86 @@ +//=================================================================== +// +// AffectorEnvironment.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//=================================================================== + +#ifndef INCLUDED_AffectorEnvironment_H +#define INCLUDED_AffectorEnvironment_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorEnvironment : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable int m_cachedFamilyId; + mutable EnvironmentGroup::Info m_cachedEgi; + mutable float m_cachedFeatherClamp; + + //-- accessible + int m_familyId; + bool m_useFeatherClampOverride; + float m_featherClampOverride; + +private: + + void load_0000 (Iff& iff); + +private: + + AffectorEnvironment (const AffectorEnvironment& rhs); + AffectorEnvironment& operator= (const AffectorEnvironment& rhs); + +public: + + AffectorEnvironment (); + virtual ~AffectorEnvironment (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + int getFamilyId () const; + void setFamilyId (int newFamilyId); + + bool getUseFeatherClampOverride () const; + void setUseFeatherClampOverride (bool useFeatherClampOverride); + float getFeatherClampOverride () const; + void setFeatherClampOverride (float featherClampOverride); +}; + +//------------------------------------------------------------------- + +inline int AffectorEnvironment::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline bool AffectorEnvironment::getUseFeatherClampOverride () const +{ + return m_useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +inline float AffectorEnvironment::getFeatherClampOverride () const +{ + return m_featherClampOverride; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.cpp new file mode 100644 index 00000000..afbe0f2f --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.cpp @@ -0,0 +1,101 @@ +// +// AffectorExclude.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorExclude.h" + +#include "sharedFile/Iff.h" + +//------------------------------------------------------------------- +// +// AffectorExclude +// +AffectorExclude::AffectorExclude () : + TerrainGenerator::Affector (TAG_AEXC, TGAT_exclude) +{ +} + +//------------------------------------------------------------------- + +AffectorExclude::~AffectorExclude () +{ +} + +//------------------------------------------------------------------- + +unsigned AffectorExclude::getAffectedMaps() const +{ + return TGM_exclude; +} + +//------------------------------------------------------------------- + +void AffectorExclude::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + generatorChunkData.excludeMap->setData (x, z, true); +} + +//------------------------------------------------------------------- + +void AffectorExclude::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorExclude version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorExclude::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorExclude::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.h new file mode 100644 index 00000000..64204f47 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorExclude.h @@ -0,0 +1,44 @@ +//=================================================================== +// +// AffectorExclude.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//=================================================================== + +#ifndef INCLUDED_AffectorExclude_H +#define INCLUDED_AffectorExclude_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorExclude : public TerrainGenerator::Affector +{ +private: + + void load_0000 (Iff& iff); + +private: + + AffectorExclude (const AffectorExclude& rhs); + AffectorExclude& operator= (const AffectorExclude& rhs); + +public: + + AffectorExclude (); + virtual ~AffectorExclude (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.cpp new file mode 100644 index 00000000..9cf6883a --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.cpp @@ -0,0 +1,383 @@ +//=================================================================== +// +// AffectorFloraDynamic.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorFloraDynamic.h" + +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedFile/Iff.h" + +//=================================================================== +// +// AffectorFloraDynamic +// +AffectorFloraDynamic::AffectorFloraDynamic (const Tag newTag, const TerrainGeneratorAffectorType newType) : + TerrainGenerator::Affector (newTag, newType), + cachedFamilyId (-1), + cachedRgi (), + cachedDensity (0.f), + familyId (0), + operation (TGO_add), + removeAll (false), + densityOverride (false), + densityOverrideDensity (1.f) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraDynamic::~AffectorFloraDynamic () +{ +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::setFamilyId (const int newFamilyId) +{ + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::setRemoveAll (const bool newRemoveAll) +{ + removeAll = newRemoveAll; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::setDensityOverride (const bool newDensityOverride) +{ + densityOverride = newDensityOverride; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::setDensityOverrideDensity (const float newDensityOverrideDensity) +{ + densityOverrideDensity = newDensityOverrideDensity; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::prepare () +{ + cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (generatorChunkData.m_legacyRandomGenerator) + { + _legacyAffect(worldX, worldZ, x, z, amount, generatorChunkData); + return; + } + if (amount > 0.f) + { + Array2d* const floraMap = getFloraMap (generatorChunkData); + + if (removeAll) + { + //-- we want to remove all radial + floraMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + DEBUG_FATAL (familyId == 0, ("familyId == 0 for %s", getName ())); + + if (cachedFamilyId != familyId) + { + cachedFamilyId = familyId; + cachedRgi = generatorChunkData.radialGroup->chooseRadial (familyId); + cachedDensity = generatorChunkData.radialGroup->getFamilyDensity (familyId); + } + + //-- do we place flora here? + const float density = densityOverride ? densityOverrideDensity : cachedDensity; + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + + if (randomGenerator.randomFloat() <= amount * density) + { + RadialGroup::Info rgi = cachedRgi; + + if (rgi.getFamilyId() != 0) + { + switch (operation) + { + case TGO_add: + { + rgi.setChildChoice(randomGenerator.randomFloat()); + + floraMap->setData (x, z, rgi); + } + break; + + case TGO_replace: + { + //-- replace is a remove of a specific type + if (floraMap->getData(x, z).getFamilyId() == familyId) + floraMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + break; + + case TGO_subtract: + case TGO_multiply: + case TGO_COUNT: + default: + DEBUG_FATAL (true, ("invalid operation")); + } + } + } + } + } + +} + +void AffectorFloraDynamic::_legacyAffect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + Array2d* const floraMap = getFloraMap (generatorChunkData); + + if (removeAll) + { + //-- we want to remove all radial + floraMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + DEBUG_FATAL (familyId == 0, ("familyId == 0 for %s", getName ())); + + if (cachedFamilyId != familyId) + { + cachedFamilyId = familyId; + cachedRgi = generatorChunkData.radialGroup->chooseRadial (familyId); + cachedDensity = generatorChunkData.radialGroup->getFamilyDensity (familyId); + } + + //-- do we place flora here? + const float density = densityOverride ? densityOverrideDensity : cachedDensity; + + if (generatorChunkData.m_legacyRandomGenerator->randomReal (0.f, 1.f) <= amount * density) + { + RadialGroup::Info rgi = cachedRgi; + + if (rgi.getFamilyId() != 0) + { + switch (operation) + { + case TGO_add: + { + rgi.setChildChoice(generatorChunkData.m_legacyRandomGenerator->randomReal(0.f, 1.f)); + + floraMap->setData (x, z, rgi); + } + break; + + case TGO_replace: + { + //-- replace is a remove of a specific type + if (floraMap->getData(x, z).getFamilyId() == familyId) + floraMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + break; + + case TGO_subtract: + case TGO_multiply: + case TGO_COUNT: + default: + DEBUG_FATAL (true, ("invalid operation")); + } + } + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorFloraDynamic version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + familyId = iff.read_int32 (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + removeAll = iff.read_int32 () != 0; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + removeAll = iff.read_int32 () != 0; + + densityOverride = iff.read_int32 () != 0; + densityOverrideDensity = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorFloraDynamic::save (Iff& iff) const +{ + iff.insertForm (TAG_0002); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (familyId); + iff.insertChunkData (static_cast (operation)); + iff.insertChunkData (removeAll ? static_cast (1) : static_cast (0)); + iff.insertChunkData (densityOverride ? static_cast (1) : static_cast (0)); + iff.insertChunkData (densityOverrideDensity); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//=================================================================== + +AffectorFloraDynamicNearConstant::AffectorFloraDynamicNearConstant () : + AffectorFloraDynamic (TAG_AFDN, TGAT_floraDynamicNearConstant) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraDynamicNearConstant::~AffectorFloraDynamicNearConstant () +{ +} + +//------------------------------------------------------------------- + +unsigned AffectorFloraDynamicNearConstant::getAffectedMaps() const +{ + return TGM_floraDynamicNear; +} + +//=================================================================== +// +// AffectorFloraFloraDynamicFarConstant +// + +AffectorFloraDynamicFarConstant::AffectorFloraDynamicFarConstant () : + AffectorFloraDynamic (TAG_AFDF, TGAT_floraDynamicFarConstant) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraDynamicFarConstant::~AffectorFloraDynamicFarConstant () +{ +} + +//------------------------------------------------------------------- + +unsigned AffectorFloraDynamicFarConstant::getAffectedMaps() const +{ + return TGM_floraDynamicFar; +} + + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.h new file mode 100644 index 00000000..52f54f16 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraDynamic.h @@ -0,0 +1,170 @@ +//=================================================================== +// +// AffectorFloraDynamic.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_AffectorFloraDynamic_H +#define INCLUDED_AffectorFloraDynamic_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorFloraDynamic : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable int cachedFamilyId; + mutable RadialGroup::Info cachedRgi; + mutable float cachedDensity; + + //-- accessible + int familyId; + TerrainGeneratorOperation operation; + bool removeAll; + bool densityOverride; + float densityOverrideDensity; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + +private: + + AffectorFloraDynamic (const AffectorFloraDynamic& rhs); + AffectorFloraDynamic& operator= (const AffectorFloraDynamic& rhs); + +protected: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const=0; + + void _legacyAffect(float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraDynamic (Tag newTag, TerrainGeneratorAffectorType newType); + virtual ~AffectorFloraDynamic (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + + int getFamilyId () const; + void setFamilyId (int newFamilyId); + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + bool getRemoveAll () const; + void setRemoveAll (bool newRemoveAll); + + bool getDensityOverride () const; + void setDensityOverride (bool newDensityOverride); + float getDensityOverrideDensity () const; + void setDensityOverrideDensity (float newDensityOverrideDensity); +}; + +//------------------------------------------------------------------- + +inline int AffectorFloraDynamic::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorFloraDynamic::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline bool AffectorFloraDynamic::getRemoveAll () const +{ + return removeAll; +} + +//------------------------------------------------------------------- + +inline bool AffectorFloraDynamic::getDensityOverride () const +{ + return densityOverride; +} + +//------------------------------------------------------------------- + +inline float AffectorFloraDynamic::getDensityOverrideDensity () const +{ + return densityOverrideDensity; +} + +//=================================================================== + +class AffectorFloraDynamicNearConstant : public AffectorFloraDynamic +{ +private: + + AffectorFloraDynamicNearConstant (const AffectorFloraDynamicNearConstant& rhs); + AffectorFloraDynamicNearConstant& operator= (const AffectorFloraDynamicNearConstant& rhs); + +private: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraDynamicNearConstant (); + virtual ~AffectorFloraDynamicNearConstant (); + + virtual unsigned getAffectedMaps() const; +}; + +//------------------------------------------------------------------- + +inline Array2d* AffectorFloraDynamicNearConstant::getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + return generatorChunkData.floraDynamicNearMap; +} + +//=================================================================== + +class AffectorFloraDynamicFarConstant : public AffectorFloraDynamic +{ +private: + + AffectorFloraDynamicFarConstant (const AffectorFloraDynamicFarConstant& rhs); + AffectorFloraDynamicFarConstant& operator= (const AffectorFloraDynamicFarConstant& rhs); + +private: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraDynamicFarConstant (); + virtual ~AffectorFloraDynamicFarConstant (); + + virtual unsigned getAffectedMaps() const; +}; + +//------------------------------------------------------------------- + +inline Array2d* AffectorFloraDynamicFarConstant::getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + return generatorChunkData.floraDynamicFarMap; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.cpp new file mode 100644 index 00000000..cd3a0b87 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.cpp @@ -0,0 +1,431 @@ +//=================================================================== +// +// AffectorFloraStatic.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorFloraStatic.h" + +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedFile/Iff.h" + +//=================================================================== +// +// AffectorFloraStatic +// +AffectorFloraStatic::AffectorFloraStatic (const Tag newTag, const TerrainGeneratorAffectorType newType) : + TerrainGenerator::Affector (newTag, newType), + cachedFamilyId (-1), + cachedFgi (), + cachedDensity (0.f), + familyId (0), + operation (TGO_add), + removeAll (false), + densityOverride (false), + densityOverrideDensity (1.f) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraStatic::~AffectorFloraStatic () +{ +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::setFamilyId (const int newFamilyId) +{ + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::setRemoveAll (const bool newRemoveAll) +{ + removeAll = newRemoveAll; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::setDensityOverride (const bool newDensityOverride) +{ + densityOverride = newDensityOverride; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::setDensityOverrideDensity (const float newDensityOverrideDensity) +{ + densityOverrideDensity = newDensityOverrideDensity; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::prepare () +{ + cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +unsigned AffectorFloraStaticCollidableConstant::getAffectedMaps() const +{ + return TGM_floraStaticCollidable; +} + +//------------------------------------------------------------------- + +unsigned AffectorFloraStaticNonCollidableConstant::getAffectedMaps() const +{ + return TGM_floraStaticNonCollidable; +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (generatorChunkData.m_legacyRandomGenerator) + { + _legacyAffect(worldX, worldZ, x, z, amount, generatorChunkData); + return; + } + if (amount > 0.f) + { + Array2d* const floraMap = getFloraMap (generatorChunkData); + + if (removeAll) + { + //-- we want to remove all flora + floraMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + } + else + { + DEBUG_FATAL (familyId == 0, ("familyId == 0 for %s", getName ())); + + if (cachedFamilyId != familyId) + { + cachedFamilyId = familyId; + cachedFgi = generatorChunkData.floraGroup->chooseFlora (familyId); + cachedDensity = generatorChunkData.floraGroup->getFamilyDensity (familyId); + } + + //-- do we place flora here? + const float density = densityOverride ? densityOverrideDensity : cachedDensity; + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + + float rf = randomGenerator.randomFloat(); + if (rf <= amount * density) + { + FloraGroup::Info fgi = cachedFgi; + + if (fgi.getFamilyId () != 0) + { + switch (operation) + { + case TGO_add: + { + rf = randomGenerator.randomFloat(); + fgi.setChildChoice(rf); + + floraMap->setData (x, z, fgi); + } + break; + + case TGO_replace: + { + //-- replace is a remove of a specific type + if (floraMap->getData (x, z).getFamilyId () == familyId) + floraMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + } + break; + + case TGO_subtract: + case TGO_multiply: + case TGO_COUNT: + default: + DEBUG_FATAL (true, ("invalid operation")); + } + } + } + } + } +} + +void AffectorFloraStatic::_legacyAffect(float /*worldX*/, float /*worldZ*/, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + Array2d* const floraMap = getFloraMap (generatorChunkData); + + if (removeAll) + { + //-- we want to remove all flora + floraMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + } + else + { + DEBUG_FATAL (familyId == 0, ("familyId == 0 for %s", getName ())); + + if (cachedFamilyId != familyId) + { + cachedFamilyId = familyId; + cachedFgi = generatorChunkData.floraGroup->chooseFlora (familyId); + cachedDensity = generatorChunkData.floraGroup->getFamilyDensity (familyId); + } + + //-- do we place flora here? + const float density = densityOverride ? densityOverrideDensity : cachedDensity; + + if (generatorChunkData.m_legacyRandomGenerator->randomReal (0.f, 1.f) <= amount * density) + { + FloraGroup::Info fgi = cachedFgi; + + if (fgi.getFamilyId () != 0) + { + switch (operation) + { + case TGO_add: + { + fgi.setChildChoice (generatorChunkData.m_legacyRandomGenerator->randomReal (0.0f, 1.0f)); + + floraMap->setData (x, z, fgi); + } + break; + + case TGO_replace: + { + //-- replace is a remove of a specific type + if (floraMap->getData (x, z).getFamilyId () == familyId) + floraMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + } + break; + + case TGO_subtract: + case TGO_multiply: + case TGO_COUNT: + default: + DEBUG_FATAL (true, ("invalid operation")); + } + } + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorFloraStatic version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + operation = TGO_replace; + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + operation = TGO_replace; + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= static_cast (TGO_COUNT), ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= static_cast (TGO_COUNT), ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + removeAll = iff.read_int32 () != 0; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + familyId = iff.read_int32 (); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= static_cast (TGO_COUNT), ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + removeAll = iff.read_int32 () != 0; + + densityOverride = iff.read_int32 () != 0; + densityOverrideDensity = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorFloraStatic::save (Iff& iff) const +{ + iff.insertForm (TAG_0004); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + iff.insertChunkData (familyId); + iff.insertChunkData (static_cast (operation)); + iff.insertChunkData (removeAll ? static_cast (1) : static_cast (0)); + iff.insertChunkData (densityOverride ? static_cast (1) : static_cast (0)); + iff.insertChunkData (densityOverrideDensity); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//=================================================================== +// +// AffectorFloraStaticCollidableConstant +// + +AffectorFloraStaticCollidableConstant::AffectorFloraStaticCollidableConstant () : + AffectorFloraStatic (TAG_AFSC, TGAT_floraStaticCollidableConstant) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraStaticCollidableConstant::~AffectorFloraStaticCollidableConstant () +{ +} + +//=================================================================== +// +// AffectorFloraStaticNonCollidableConstant +// + +AffectorFloraStaticNonCollidableConstant::AffectorFloraStaticNonCollidableConstant () : + AffectorFloraStatic (TAG_AFSN, TGAT_floraStaticNonCollidableConstant) +{ +} + +//------------------------------------------------------------------- + +AffectorFloraStaticNonCollidableConstant::~AffectorFloraStaticNonCollidableConstant () +{ +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.h new file mode 100644 index 00000000..74811407 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorFloraStatic.h @@ -0,0 +1,171 @@ +//=================================================================== +// +// AffectorFloraStatic.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//=================================================================== + +#ifndef INCLUDED_AffectorFloraStatic_H +#define INCLUDED_AffectorFloraStatic_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorFloraStatic : public TerrainGenerator::Affector +{ +protected: + + //-- not accessible + mutable int cachedFamilyId; + mutable FloraGroup::Info cachedFgi; + mutable float cachedDensity; + + //-- accessible + int familyId; + TerrainGeneratorOperation operation; + bool removeAll; + bool densityOverride; + float densityOverrideDensity; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + +private: + + AffectorFloraStatic (const AffectorFloraStatic& rhs); + AffectorFloraStatic& operator= (const AffectorFloraStatic& rhs); + +protected: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const=0; + + void _legacyAffect(float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraStatic (Tag newTag, TerrainGeneratorAffectorType newType); + virtual ~AffectorFloraStatic (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + + int getFamilyId () const; + void setFamilyId (int newFamilyId); + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + bool getRemoveAll () const; + void setRemoveAll (bool newRemoveAll); + + bool getDensityOverride () const; + void setDensityOverride (bool newDensityOverride); + float getDensityOverrideDensity () const; + void setDensityOverrideDensity (float newDensityOverrideDensity); +}; + +//------------------------------------------------------------------- + +inline int AffectorFloraStatic::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorFloraStatic::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline bool AffectorFloraStatic::getRemoveAll () const +{ + return removeAll; +} + +//------------------------------------------------------------------- + +inline bool AffectorFloraStatic::getDensityOverride () const +{ + return densityOverride; +} + +//------------------------------------------------------------------- + +inline float AffectorFloraStatic::getDensityOverrideDensity () const +{ + return densityOverrideDensity; +} + +//------------------------------------------------------------------- + +class AffectorFloraStaticCollidableConstant : public AffectorFloraStatic +{ +private: + + AffectorFloraStaticCollidableConstant (const AffectorFloraStaticCollidableConstant& rhs); + AffectorFloraStaticCollidableConstant& operator= (const AffectorFloraStaticCollidableConstant& rhs); + +private: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraStaticCollidableConstant (); + virtual ~AffectorFloraStaticCollidableConstant (); + virtual unsigned getAffectedMaps() const; +}; + +//------------------------------------------------------------------- + +inline Array2d* AffectorFloraStaticCollidableConstant::getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + return generatorChunkData.floraStaticCollidableMap; +} + +//------------------------------------------------------------------- + +class AffectorFloraStaticNonCollidableConstant : public AffectorFloraStatic +{ +private: + + AffectorFloraStaticNonCollidableConstant (const AffectorFloraStaticNonCollidableConstant& rhs); + AffectorFloraStaticNonCollidableConstant& operator= (const AffectorFloraStaticNonCollidableConstant& rhs); + +private: + + virtual Array2d* getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorFloraStaticNonCollidableConstant (); + virtual ~AffectorFloraStaticNonCollidableConstant (); + virtual unsigned getAffectedMaps() const; +}; + +//------------------------------------------------------------------- + +inline Array2d* AffectorFloraStaticNonCollidableConstant::getFloraMap (const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + return generatorChunkData.floraStaticNonCollidableMap; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.cpp new file mode 100644 index 00000000..6abbed69 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.cpp @@ -0,0 +1,731 @@ +// +// AffectorHeight.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorHeight.h" + +#include "sharedFile/Iff.h" +#include "sharedFractal/MultiFractal.h" +#include "sharedFractal/MultiFractalReaderWriter.h" +#include "sharedTerrain/Affector.h" + +//------------------------------------------------------------------- +// +// AffectorHeightConstant +// +AffectorHeightConstant::AffectorHeightConstant () : + TerrainGenerator::Affector (TAG_AHCN, TGAT_heightConstant), + operation (TGO_replace), + height (0) +{ +} + +//------------------------------------------------------------------- + +AffectorHeightConstant::~AffectorHeightConstant () +{ +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::setOperation (const TerrainGeneratorOperation newOperation) +{ + operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::setHeight (const float newHeight) +{ + height = newHeight; +} + +//------------------------------------------------------------------- + +unsigned AffectorHeightConstant::getAffectedMaps() const +{ + return TGM_height; +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + float newHeight = 0.f; + + switch (operation) + { + case TGO_add: + newHeight = generatorChunkData.heightMap->getData (x, z) + amount*height; + break; + + case TGO_subtract: + newHeight = generatorChunkData.heightMap->getData (x, z) - amount*height; + break; + + case TGO_multiply: + { + const float oldHeight = generatorChunkData.heightMap->getData (x, z); + const float desiredHeight = generatorChunkData.heightMap->getData (x, z) * height; + newHeight = linearInterpolate (oldHeight, desiredHeight, amount); + } + break; + + case TGO_replace: + default: + newHeight = amount * height + (1.f - amount) * generatorChunkData.heightMap->getData (x, z); + break; + + case TGO_COUNT: + FATAL (true, ("invalid operation")); + break; + } + + generatorChunkData.heightMap->setData (x, z, newHeight); + } +} + +//------------------------------------------------------------------- + +bool AffectorHeightConstant::affectsHeight () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorHeightConstant version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s", getName ())); + operation = static_cast (newOperation); + + height = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorHeightConstant::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (operation)); + iff.insertChunkData (height); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- +// +// AffectorHeightFractal +// +AffectorHeightFractal::AffectorHeightFractal () : + TerrainGenerator::Affector (TAG_AHFR, TGAT_heightFractal), + m_multiFractal (0), + m_cachedFamilyId (-1), + m_familyId (0), + m_scaleY (1), + m_operation (TGO_replace) +{ +} + +AffectorHeightFractal::~AffectorHeightFractal () +{ + m_multiFractal = 0; +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::setOperation (const TerrainGeneratorOperation newOperation) +{ + m_operation = newOperation; +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::setFamilyId (const int newFamilyId) +{ + m_familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::setScaleY (const float newScale) +{ + m_scaleY = newScale; +} + +//------------------------------------------------------------------- + +unsigned AffectorHeightFractal::getAffectedMaps() const +{ + return TGM_height; +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_multiFractal = generatorChunkData.fractalGroup->getFamilyMultiFractal (m_familyId); + } + + NOT_NULL (m_multiFractal); + + const float fractalHeight = m_scaleY * m_multiFractal->getValueCache (worldX, worldZ, x, z); + const float oldHeight = generatorChunkData.heightMap->getData (x, z); + + float newHeight = oldHeight; + + switch (m_operation) + { + case TGO_add: + newHeight += amount * fractalHeight; + break; + + case TGO_subtract: + newHeight -= amount * fractalHeight; + break; + + case TGO_multiply: + { + const float desiredHeight = oldHeight * fractalHeight; + + newHeight = linearInterpolate (oldHeight, desiredHeight, amount); + } + break; + + case TGO_replace: + default: + newHeight = linearInterpolate (oldHeight, fractalHeight, amount); + break; + + case TGO_COUNT: + FATAL (true, ("invalid operation")); + break; + } + + generatorChunkData.heightMap->setData (x, z, newHeight); + } +} + +//------------------------------------------------------------------- + +bool AffectorHeightFractal::affectsHeight () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::load (Iff& iff, FractalGroup& fractalGroup) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff, fractalGroup); + break; + + case TAG_0001: + load_0001 (iff, fractalGroup); + break; + + case TAG_0002: + load_0002 (iff, fractalGroup); + break; + + case TAG_0003: + load_0003 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorHeightFractal version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::load_0000 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + setOperation (static_cast (newOperation)); + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + const Vector scale = iff.read_floatVector (); + multiFractal.setScale (scale.x, scale.z); + + setScaleY (scale.y); + + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::load_0001 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + setOperation (static_cast (newOperation)); + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + multiFractal.setNumberOfOctaves (iff.read_int32 ()); + multiFractal.setFrequency (iff.read_float ()); + + Vector scale; + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + const int unused = iff.read_int32 (); + UNREF (unused); + scale.x = iff.read_float (); + scale.z = iff.read_float (); + } + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + for (i = 0; i < multiFractal.getNumberOfOctaves (); i++) + { + const int dummy1 = iff.read_int32 (); + UNREF (dummy1); + + const int dummy2 = iff.read_int32 (); + UNREF (dummy2); + } + + setScaleY (iff.read_float ()); + + multiFractal.setScale (scale.x, scale.z); + + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::load_0002 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load the fractal settings + MultiFractal multiFractal; + MultiFractalReaderWriter::load (iff, multiFractal); + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + setOperation (static_cast (newOperation)); + + setScaleY (iff.read_float ()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFamilyId (iff.read_int32 ()); + + int newOperation = iff.read_int32 (); + DEBUG_FATAL (newOperation < 0 || newOperation >= TGO_COUNT, ("operation out of bounds for %s (%i)", getName (), newOperation)); + setOperation (static_cast (newOperation)); + + setScaleY (iff.read_float ()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorHeightFractal::save (Iff& iff) const +{ + iff.insertForm (TAG_0003); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + iff.insertChunk (TAG (P,A,R,M)); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (static_cast (getOperation ())); + iff.insertChunkData (getScaleY ()); + + iff.exitChunk (); + + iff.exitForm (); + + iff.exitForm (); +} + +//------------------------------------------------------------------- +// +// AffectorHeightTerrace +// +AffectorHeightTerrace::AffectorHeightTerrace () : + TerrainGenerator::Affector (TAG_AHTR, TGAT_heightTerrace), + height (20.0f), + fraction (0.25f) +{ +} + +//------------------------------------------------------------------- + +AffectorHeightTerrace::~AffectorHeightTerrace () +{ +} + +//------------------------------------------------------------------- + +unsigned AffectorHeightTerrace::getAffectedMaps() const +{ + return TGM_height; +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f && height > 0.f) + { + const float terraceHeight = height; + + if (terraceHeight > 0.f) + { + const float originalHeight = generatorChunkData.heightMap->getData (x, z); + const float lowHeight = originalHeight - ((originalHeight < 0) ? (terraceHeight + fmodf (originalHeight, terraceHeight)) : fmodf (originalHeight, terraceHeight)); + const float midHeight = lowHeight + terraceHeight * fraction; + const float highHeight = lowHeight + terraceHeight; + + float newHeight = lowHeight; + + if (originalHeight > midHeight) + { + const float t = (originalHeight - midHeight) / (highHeight - midHeight); + + newHeight = linearInterpolate (lowHeight, highHeight, t); + } + + generatorChunkData.heightMap->setData (x, z, linearInterpolate (originalHeight, newHeight, amount)); + } + } +} + +//------------------------------------------------------------------- + +bool AffectorHeightTerrace::affectsHeight () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorHeightTerrace version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + fraction = iff.read_float (); + height = iff.read_float (); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + fraction = iff.read_float (); + height = iff.read_float (); + iff.exitChunk (TAG_DATA, true); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + fraction = iff.read_float (); + height = iff.read_float (); + iff.exitChunk (TAG_DATA, true); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load the fractal settings + { + MultiFractal multiFractal; + MultiFractalReaderWriter::load (iff, multiFractal); + } + + //-- load parameters + iff.enterChunk (TAG_PARM); + + fraction = iff.read_float (); + height = iff.read_float (); + const int unused = iff.read_int32 (); + UNREF (unused); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + fraction = iff.read_float (); + height = iff.read_float (); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::save (Iff& iff) const +{ + iff.insertForm (TAG_0004); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + iff.insertChunkData (fraction); + iff.insertChunkData (height); + iff.exitChunk (); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::setHeight (const float newHeight) +{ + height = newHeight; +} + +//------------------------------------------------------------------- + +void AffectorHeightTerrace::setFraction (const float newFraction) +{ + fraction = newFraction; +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.h new file mode 100644 index 00000000..6ab3997a --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorHeight.h @@ -0,0 +1,193 @@ +//=================================================================== +// +// AffectorHeight.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_AffectorHeight_H +#define INCLUDED_AffectorHeight_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorHeightConstant : public TerrainGenerator::Affector +{ +private: + + //-- accessible + TerrainGeneratorOperation operation; + float height; + +private: + + void load_0000 (Iff& iff); + +private: + + AffectorHeightConstant (const AffectorHeightConstant& rhs); + AffectorHeightConstant& operator= (const AffectorHeightConstant& rhs); + +public: + + AffectorHeightConstant (); + virtual ~AffectorHeightConstant (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual bool affectsHeight () const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + float getHeight () const; + void setHeight (float newHeight); +}; + +//------------------------------------------------------------------- + +inline TerrainGeneratorOperation AffectorHeightConstant::getOperation () const +{ + return operation; +} + +//------------------------------------------------------------------- + +inline float AffectorHeightConstant::getHeight () const +{ + return height; +} + +//=================================================================== + +class AffectorHeightFractal : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable const MultiFractal* m_multiFractal; + mutable int m_cachedFamilyId; + + //-- accessible + int m_familyId; + float m_scaleY; + TerrainGeneratorOperation m_operation; + +private: + + void load_0000 (Iff& iff, FractalGroup& fractalGroup); + void load_0001 (Iff& iff, FractalGroup& fractalGroup); + void load_0002 (Iff& iff, FractalGroup& fractalGroup); + void load_0003 (Iff& iff); + +private: + + AffectorHeightFractal (const AffectorHeightFractal& rhs); + AffectorHeightFractal& operator= (const AffectorHeightFractal& rhs); + +public: + + AffectorHeightFractal (); + virtual ~AffectorHeightFractal (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual bool affectsHeight () const; + virtual void load (Iff& iff, FractalGroup& fractalGroup); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + TerrainGeneratorOperation getOperation () const; + void setOperation (TerrainGeneratorOperation newOperation); + + int getFamilyId () const; + void setFamilyId (int id); + + float getScaleY () const; + void setScaleY (float newScaleY); +}; + +//=================================================================== + +inline TerrainGeneratorOperation AffectorHeightFractal::getOperation () const +{ + return m_operation; +} + +//------------------------------------------------------------------- + +inline int AffectorHeightFractal::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline float AffectorHeightFractal::getScaleY () const +{ + return m_scaleY; +} + +//=================================================================== + +class AffectorHeightTerrace : public TerrainGenerator::Affector +{ +private: + + float height; + float fraction; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + +private: + + AffectorHeightTerrace (const AffectorHeightTerrace& rhs); + AffectorHeightTerrace& operator= (const AffectorHeightTerrace& rhs); + +public: + + AffectorHeightTerrace (); + virtual ~AffectorHeightTerrace (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual bool affectsHeight () const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + float getHeight () const; + void setHeight (float newHeight); + + float getFraction () const; + void setFraction (float newFraction); +}; + +//------------------------------------------------------------------- + +inline float AffectorHeightTerrace::getHeight () const +{ + return height; +} + +//------------------------------------------------------------------- + +inline float AffectorHeightTerrace::getFraction () const +{ + return fraction; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.cpp new file mode 100644 index 00000000..5ccc51cf --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.cpp @@ -0,0 +1,137 @@ +// ====================================================================== +// +// AffectorPassable.cpp +// Copyright 2004 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorPassable.h" + +#include "sharedFile/Iff.h" + +//------------------------------------------------------------------- +// +// AffectorExclude +// +AffectorPassable::AffectorPassable () : +TerrainGenerator::Affector (TAG_APAS, TGAT_passable), +m_passable(true), +m_featherThreshold(0.0f) +{ +} + +//------------------------------------------------------------------- + +AffectorPassable::~AffectorPassable () +{ +} + +//------------------------------------------------------------------- + +unsigned AffectorPassable::getAffectedMaps() const +{ + return TGM_passable; +} + +//------------------------------------------------------------------- + +void AffectorPassable::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount >= m_featherThreshold) + generatorChunkData.passableMap->setData (x, z, m_passable); +} + +//------------------------------------------------------------------- + +void AffectorPassable::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorPassable version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorPassable::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + { + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + { + m_passable = iff.read_bool8(); + m_featherThreshold = iff.read_float(); + } + iff.exitChunk (TAG_DATA); + } + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorPassable::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + { + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + { + iff.insertChunkData(m_passable); + iff.insertChunkData(m_featherThreshold); + } + iff.exitChunk (TAG_DATA); + } + iff.exitForm (TAG_0000); +} + +//---------------------------------------------------------------------- + +bool AffectorPassable::isPassable() const +{ + return m_passable; +} + +//---------------------------------------------------------------------- + +float AffectorPassable::getFeatherThreshold() const +{ + return m_featherThreshold; +} + +//---------------------------------------------------------------------- + +void AffectorPassable::setPassable(bool const passable) +{ + m_passable = passable; +} + +//---------------------------------------------------------------------- + +void AffectorPassable::setFeatherThreshold(float const featherThreshold) +{ + m_featherThreshold = featherThreshold; +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.h new file mode 100644 index 00000000..639a47d7 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorPassable.h @@ -0,0 +1,53 @@ +//====================================================================== +// +// AffectorPassable.h +// copyright (c) 2004 Sony Online Entertainment +// +//====================================================================== + +#ifndef INCLUDED_AffectorPassable_H +#define INCLUDED_AffectorPassable_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorPassable : public TerrainGenerator::Affector +{ +private: + + void load_0000 (Iff& iff); + +private: + + AffectorPassable (const AffectorPassable& rhs); + AffectorPassable& operator= (const AffectorPassable& rhs); + +public: + + AffectorPassable (); + virtual ~AffectorPassable (); + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual unsigned getAffectedMaps() const; + + bool isPassable() const; + float getFeatherThreshold() const; + + void setPassable(bool passable); + void setFeatherThreshold(float featherThreshold); + +private: + + bool m_passable; + float m_featherThreshold; + +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.cpp new file mode 100644 index 00000000..4fd92ddf --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.cpp @@ -0,0 +1,749 @@ +// +// AffectorRibbon.cpp +// +// copyright 2005, Sony Online Entertainment +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorRibbon.h" + +#include "sharedFile/Iff.h" +#include "sharedMath/Vector2d.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/CoordinateHash.h" + +//------------------------------------------------------------------- +// +// AffectorRibbon +// +AffectorRibbon::AffectorRibbon () : + AffectorBoundaryPoly (TAG_ARIB, TGAT_ribbon), + m_cachedTerrainShaderFamilyId (-1), + m_cachedSgi (), + m_waterShaderSize(64.0f), + m_velocity(1.0f), + m_capWidth(4.0f), + m_terrainShaderFamilyId (0), + m_featherFunctionTerrainShader (TGFF_linear), + m_featherDistanceTerrainShader (0.5f), + m_ribbonWaterShaderTemplateName (0), + m_waterType(TGWT_water), + m_heightList (), + m_endCapPointList (), + m_endCapExtent() +{ +} + +//------------------------------------------------------------------- + +AffectorRibbon::~AffectorRibbon () +{ + if (m_ribbonWaterShaderTemplateName) + { + delete [] m_ribbonWaterShaderTemplateName; + m_ribbonWaterShaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setWaterShaderSize (float val) +{ + m_waterShaderSize = val; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setVelocity (float val) +{ + m_velocity = val; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setCapWidth (float val) +{ + m_capWidth = val; +} + +//------------------------------------------------------------------- +bool AffectorRibbon::affectsHeight () const +{ + return false; +} + + +//------------------------------------------------------------------- + +void AffectorRibbon::setTerrainShaderFamilyId (const int newFamilyId) +{ + m_terrainShaderFamilyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setFeatherFunctionTerrainShader (TerrainGeneratorFeatherFunction newFeatherFunction) +{ + m_featherFunctionTerrainShader = newFeatherFunction; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setFeatherDistanceTerrainShader (const float newFeatherDistance) +{ + m_featherDistanceTerrainShader = newFeatherDistance; +} + +//------------------------------------------------------------------- + +bool AffectorRibbon::affectsShader () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::prepare () +{ + m_cachedTerrainShaderFamilyId = -1; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::copyHeightList (const ArrayList& newHeightList) +{ + m_heightList = newHeightList; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::createInitialHeightList () +{ + m_heightList.clear (); + int size = m_pointList.getNumberOfElements (); + for(int i = 0; i < size; i++) + { + m_heightList.add(0.0f); + } +} + +//------------------------------------------------------------------- + +void AffectorRibbon::generateEndCapPointList () +{ + // tapered square - 8 sides - not a perfect octagon + m_endCapPointList.clear(); + + if(m_capWidth > 0 && m_pointList.getNumberOfElements() > 1) + { + Vector2d up_vect = m_pointList[0] - m_pointList[1]; + up_vect.normalize(); + Vector2d down_vect = -up_vect; + Vector2d right_vect = Vector2d(up_vect.y,-up_vect.x); + Vector2d left_vect = -right_vect; + + // 0 + Vector2d currentPoint = m_pointList[0] + (left_vect * m_capWidth/2.0f); + m_endCapPointList.add(currentPoint); + + up_vect *= m_capWidth; + down_vect *= m_capWidth; + right_vect *= m_capWidth; + left_vect *= m_capWidth; + + // 1 + currentPoint = m_endCapPointList[0] + up_vect + left_vect; + m_endCapPointList.add(currentPoint); + + // 2 + currentPoint = m_endCapPointList[1] + up_vect; + m_endCapPointList.add(currentPoint); + + // 3 + currentPoint = m_endCapPointList[2] + right_vect + up_vect; + m_endCapPointList.add(currentPoint); + + // 4 + currentPoint = m_endCapPointList[3] + right_vect; + m_endCapPointList.add(currentPoint); + + // 5 + currentPoint = m_endCapPointList[4] + down_vect + right_vect; + m_endCapPointList.add(currentPoint); + + // 6 + currentPoint = m_endCapPointList[5] + down_vect; + m_endCapPointList.add(currentPoint); + + // 7 + currentPoint = m_endCapPointList[6] + left_vect + down_vect; + m_endCapPointList.add(currentPoint); + + + } +} + +//------------------------------------------------------------------- + +unsigned AffectorRibbon::getAffectedMaps() const +{ + return unsigned(TGM_ALL); + // TODO - make this correctly report the maps set by 'affect' +} + +//------------------------------------------------------------------- + +void AffectorRibbon::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (!isEnabled ()) + return; + + if (m_terrainShaderFamilyId == 0) + return; + + + if (amount > 0.f) + { + if (m_extent.isWithin (worldX, worldZ)) + { + const float width_2 = m_width * 0.5f; + bool found = false; + FindData result; + if (find (Vector2d (worldX, worldZ), width_2, result,true)) // check the strip + { + const float distanceToCenter = fabsf (result.distanceToCenter); + if (WithinRangeInclusiveInclusive (0.f, distanceToCenter, width_2 * (1.f - getFeatherDistanceTerrainShader ()))) + { + found = true; + } + } + if(!found && m_endCapExtent.isWithin(worldX, worldZ)) // check the endcap + { + Vector2d centerOfEndCap = m_endCapExtent.getCenter(); + const float distanceToCenter = centerOfEndCap.magnitudeBetween(Vector2d(worldX,worldZ)); + if(WithinRangeInclusiveInclusive (0.f, distanceToCenter, (width_2 * 3.0f) * (1.f - getFeatherDistanceTerrainShader()))) + { + found = true; + } + } + if(found) + { + //-- set the shader + if (m_cachedTerrainShaderFamilyId != m_terrainShaderFamilyId) + { + m_cachedTerrainShaderFamilyId = m_terrainShaderFamilyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_terrainShaderFamilyId); + } + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + ShaderGroup::Info sgi = m_cachedSgi; + sgi.setChildChoice (randomGenerator.randomFloat()); + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setRibbonWaterShaderTemplateName (const char* newRibbonWaterShaderTemplateName) +{ + if (m_ribbonWaterShaderTemplateName) + { + delete [] m_ribbonWaterShaderTemplateName; + m_ribbonWaterShaderTemplateName = 0; + } + + if (newRibbonWaterShaderTemplateName) + m_ribbonWaterShaderTemplateName = DuplicateString (newRibbonWaterShaderTemplateName); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::setWaterType (TerrainGeneratorWaterType newWaterType) +{ + m_waterType = newWaterType; +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + case TAG_0001: + load_0001 (iff); + break; + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorRibbon version %s/%s", buffer, tagBuffer)); + } + break; + } + + generateEndCapPointList(); + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + m_heightData.clear(); // we don't use m_heightdata anymore + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(0.0f); + } + + setWidth (iff.read_float ()); + IGNORE_RETURN(iff.read_float ()); // old depth + setWaterShaderSize (64.0f); + setVelocity (1.0f); + setCapWidth(getWidth()); // default cap size of old ribbons to width of ribbon + IGNORE_RETURN(iff.read_int32 ()); // old forward direction + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + m_heightData.clear(); // we don't use m_heightdata anymore + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(0.0f); + } + + setWidth (iff.read_float ()); + IGNORE_RETURN(iff.read_float ()); // old depth + setWaterShaderSize (iff.read_float ()); + setVelocity (iff.read_float ()); + setCapWidth(getWidth()); // default cap size of old ribbons to width of ribbon + IGNORE_RETURN(iff.read_int32 ()); // old forward direction + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + m_heightData.clear(); // we don't use m_heightdata anymore + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(0.0f); + } + + setWidth (iff.read_float ()); + IGNORE_RETURN(iff.read_float ()); // old depth + setWaterShaderSize (iff.read_float ()); + setVelocity (iff.read_float ()); + setCapWidth(getWidth()); // default cap size of old ribbons to width of ribbon + IGNORE_RETURN(iff.read_int32 ()); // old forward direction + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + setWaterType(static_cast (iff.read_int32 ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(iff.read_float()); + } + + setWidth (iff.read_float ()); + setWaterShaderSize (iff.read_float ()); + setVelocity (iff.read_float ()); + setCapWidth(getWidth()); // default cap size of old ribbons to width of ribbon + IGNORE_RETURN(iff.read_int32 ()); // old forward direction + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + setWaterType(static_cast (iff.read_int32 ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(iff.read_float()); + } + + setWidth (iff.read_float ()); + setWaterShaderSize (iff.read_float ()); + setVelocity (iff.read_float ()); + setCapWidth(iff.read_float ()); + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + setWaterType(static_cast (iff.read_int32 ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + m_heightList.add(iff.read_float()); + } + + setWidth (iff.read_float ()); + setWaterShaderSize (iff.read_float ()); + setVelocity (iff.read_float ()); + setCapWidth(iff.read_float ()); + setTerrainShaderFamilyId(iff.read_int32()); + setFeatherFunctionTerrainShader (static_cast (iff.read_int32 ())); + const float newFeatherDistanceTerrainShader = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistanceTerrainShader (newFeatherDistanceTerrainShader); + + char* templateName = iff.read_string (); + setRibbonWaterShaderTemplateName (templateName); + delete [] templateName; + + setWaterType(static_cast (iff.read_int32 ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +void AffectorRibbon::save (Iff& iff) const +{ + iff.insertForm (TAG_0005); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + //m_heightData.save (iff); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (m_pointList.getNumberOfElements ()); + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); ++i) + { + iff.insertChunkData (getPoint (i).x); + iff.insertChunkData (getPoint (i).y); + iff.insertChunkData (m_heightList[i]); + } + + iff.insertChunkData (getWidth ()); + iff.insertChunkData (getWaterShaderSize ()); + iff.insertChunkData (getVelocity ()); + iff.insertChunkData (getCapWidth ()); + iff.insertChunkData (getTerrainShaderFamilyId ()); + iff.insertChunkData (static_cast (getFeatherFunctionTerrainShader ())); + iff.insertChunkData (getFeatherDistanceTerrainShader ()); + iff.insertChunkString (getRibbonWaterShaderTemplateName () ? getRibbonWaterShaderTemplateName () : ""); + iff.insertChunkData (static_cast (getWaterType())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +struct Segment +{ + Vector topControlPoint; + Vector bottomControlPoint; + Vector direction; + Vector topNormal; + Vector bottomNormal; + +}; + +void AffectorRibbon::createQuadList (ArrayList& quadList) const +{ + ArrayList segmentList; + + const int pointListSize = m_pointList.size(); + + if(pointListSize < 2) + { + DEBUG_FATAL(true,("void AffectorRibbon::createQuadList - less than 2 control points for ribbon")); + return; + } + + const float width = m_width/2.0f; + + // get control points, calc direction, and initial normals + int i; + for (i = 0; i < pointListSize; ++i) + { + + Segment segment; + if(i == 0) // handle first segment + { + Vector nextSegmentTopControlPoint = Vector(m_pointList[i+1].x,m_heightList[i+1],m_pointList[i+1].y); + + segment.bottomControlPoint = Vector(m_pointList[i].x,m_heightList[i],m_pointList[i].y); + segment.direction = nextSegmentTopControlPoint - segment.bottomControlPoint; + segment.direction.y = 0.0f; + segment.direction.normalize(); + segment.topControlPoint = segment.bottomControlPoint - (segment.direction * width); + segment.topNormal = segment.bottomNormal = Vector(segment.direction.z,0.0f,-segment.direction.x); + segmentList.add(segment); + } + + if(i == pointListSize - 1) // handle last segment + { + Segment lastSegment = segmentList[segmentList.size() - 1]; + segment.direction = lastSegment.direction; + segment.topControlPoint = lastSegment.bottomControlPoint; + segment.bottomControlPoint = segment.topControlPoint + (segment.direction * width); + segment.bottomControlPoint.y = segment.topControlPoint.y; + segment.topNormal = segment.bottomNormal = Vector(segment.direction.z,0.0f,-segment.direction.x); + segmentList.add(segment); + } + else // handle middle segments + { + segment.topControlPoint = Vector(m_pointList[i].x,m_heightList[i],m_pointList[i].y); + segment.bottomControlPoint = Vector(m_pointList[i+1].x,m_heightList[i+1],m_pointList[i+1].y); + segment.direction = segment.bottomControlPoint - segment.topControlPoint; + segment.direction.y = 0.0f; + segment.direction.normalize(); + segment.topNormal = segment.bottomNormal = Vector(segment.direction.z,0.0f,-segment.direction.x); + segmentList.add(segment); + } + } + + // walk through the segment list and fix the shared normals + const int segmentListSize = segmentList.size(); + for(i = 1; i < segmentListSize; i++) // skip the first segment - it's bottom normal gets fixed by the next segment + { + segmentList[i].topNormal = (segmentList[i].topNormal + segmentList[i - 1].bottomNormal) / 2.0f; + segmentList[i - 1].bottomNormal = segmentList[i].topNormal; + } + + // walk the segments and build up the points for the quad + for(i = 0; i < segmentListSize; i++) + { + AffectorRibbon::Quad quad; + + quad.points[0] = (segmentList[i].topNormal * width) + segmentList[i].topControlPoint; + quad.points[1] = (-segmentList[i].topNormal * width) + segmentList[i].topControlPoint; + quad.points[2] = (-segmentList[i].bottomNormal * width) + segmentList[i].bottomControlPoint; + quad.points[3] = (segmentList[i].bottomNormal * width) + segmentList[i].bottomControlPoint; + quadList.add (quad); + } +} + +//------------------------------------------------------------------- + +void AffectorRibbon::recalculate () +{ + AffectorBoundaryPoly::recalculate(); + + m_endCapExtent.x0 = FLT_MAX; + m_endCapExtent.y0 = FLT_MAX; + m_endCapExtent.x1 = -FLT_MAX; + m_endCapExtent.y1 = -FLT_MAX; + + int i; + for (i = 0; i < m_endCapPointList.getNumberOfElements (); ++i) + { + m_extent.expand (m_endCapPointList [i].x, m_endCapPointList [i].y); + m_endCapExtent.expand (m_endCapPointList [i].x, m_endCapPointList [i].y); + } +} + + + + + + + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.h new file mode 100644 index 00000000..d58f5aa6 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRibbon.h @@ -0,0 +1,182 @@ +//=================================================================== +// +// AffectorRibbon.h +// +// copyright 2005, Sony Online Entertainment +// + +//=================================================================== + +#ifndef INCLUDED_AffectorRibbon_H +#define INCLUDED_AffectorRibbon_H + +//=================================================================== + +#include "sharedTerrain/Affector.h" + +//=================================================================== + +class AffectorRibbon : public AffectorBoundaryPoly +{ +public: + struct Quad + { + Vector points [4]; + }; + +public: + + AffectorRibbon (); + virtual ~AffectorRibbon (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool affectsHeight () const; + virtual bool affectsShader () const; + virtual void createHeightData () {}; + virtual unsigned getAffectedMaps() const; + + void setWaterShaderSize(float val); + float getWaterShaderSize() const; + void setVelocity(float val); + float getVelocity() const; + void setCapWidth (float newCapWidth); + float getCapWidth () const; + + void createQuadList (ArrayList& quadList) const; + + const char* getRibbonWaterShaderTemplateName () const; + void setRibbonWaterShaderTemplateName (const char* newRibbonShaderTemplateName); + TerrainGeneratorWaterType getWaterType () const; + void setWaterType (TerrainGeneratorWaterType newWaterType); + const ArrayList& getHeightList () const; + void copyHeightList (const ArrayList& newHeightList); + void createInitialHeightList (); + void generateEndCapPointList (); + const ArrayList& getEndCapPointList () const; + + int getTerrainShaderFamilyId () const; + void setTerrainShaderFamilyId (int newFamilyId); + TerrainGeneratorFeatherFunction getFeatherFunctionTerrainShader () const; + void setFeatherFunctionTerrainShader (TerrainGeneratorFeatherFunction newFeatherFunction); + float getFeatherDistanceTerrainShader () const; + void setFeatherDistanceTerrainShader (float newFeatherDistance); + const Rectangle2d& getEndCapExtent() const; + + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + virtual void recalculate (); + +private: + + AffectorRibbon (const AffectorRibbon& rhs); + AffectorRibbon& operator= (const AffectorRibbon& rhs); + +private: + + mutable int m_cachedTerrainShaderFamilyId; + mutable ShaderGroup::Info m_cachedSgi; + + float m_waterShaderSize; + float m_velocity; + float m_capWidth; + int m_terrainShaderFamilyId; + TerrainGeneratorFeatherFunction m_featherFunctionTerrainShader; + float m_featherDistanceTerrainShader; + char* m_ribbonWaterShaderTemplateName; + TerrainGeneratorWaterType m_waterType; + ArrayList m_heightList; + ArrayList m_endCapPointList; + Rectangle2d m_endCapExtent; + +}; + +//------------------------------------------------------------------- + +inline float AffectorRibbon::getWaterShaderSize () const +{ + return m_waterShaderSize; +} + +//------------------------------------------------------------------- + +inline float AffectorRibbon::getVelocity () const +{ + return m_velocity; +} + +//------------------------------------------------------------------- + +inline const char* AffectorRibbon::getRibbonWaterShaderTemplateName () const +{ + return m_ribbonWaterShaderTemplateName; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorWaterType AffectorRibbon::getWaterType () const +{ + return m_waterType; +} + +//------------------------------------------------------------------- + +inline const ArrayList& AffectorRibbon::getHeightList () const +{ + return m_heightList; +} + +//------------------------------------------------------------------- + +inline float AffectorRibbon::getCapWidth () const +{ + return m_capWidth; +} + +//------------------------------------------------------------------- + +inline const ArrayList& AffectorRibbon::getEndCapPointList () const +{ + return m_endCapPointList; +} + +//------------------------------------------------------------------- + +inline int AffectorRibbon::getTerrainShaderFamilyId () const +{ + return m_terrainShaderFamilyId; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorFeatherFunction AffectorRibbon::getFeatherFunctionTerrainShader () const +{ + return m_featherFunctionTerrainShader; +} + +//------------------------------------------------------------------- + +inline float AffectorRibbon::getFeatherDistanceTerrainShader () const +{ + return m_featherDistanceTerrainShader; +} + +//------------------------------------------------------------------- + +inline const Rectangle2d& AffectorRibbon::getEndCapExtent() const +{ + return m_endCapExtent; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.cpp new file mode 100644 index 00000000..b41056dd --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.cpp @@ -0,0 +1,940 @@ +//=================================================================== +// +// AffectorRiver.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorRiver.h" + +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedFile/Iff.h" + +#include + +//=================================================================== + +AffectorRiver::AffectorRiver () : + AffectorBoundaryPoly (TAG_ARIV, TGAT_river), + m_cachedBankFamilyId (-1), + m_cachedBankSgi (), + m_cachedBottomFamilyId (-1), + m_cachedBottomSgi (), + m_multiFractal (), + m_bankFamilyId (0), + m_bottomFamilyId (0), + m_trenchDepth (0.f), + m_hasLocalWaterTable (false), + m_localWaterTableDepth (2.f), + m_localWaterTableWidth (4.f), + m_localWaterTableShaderSize (2.f), + m_localWaterTableShaderTemplateName (0), + m_velocity (0.f), + m_waterType(TGWT_water) + +{ + m_multiFractal.setScale (0.01f); + m_multiFractal.setGain (true, 0.9f); + m_multiFractal.setNumberOfOctaves (3); +} + +//------------------------------------------------------------------- + +AffectorRiver::~AffectorRiver () +{ + if (m_localWaterTableShaderTemplateName) + { + delete [] m_localWaterTableShaderTemplateName; + m_localWaterTableShaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +void AffectorRiver::setTrenchDepth (const float newTrenchDepth) +{ + m_trenchDepth = newTrenchDepth; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setVelocity (const float newVelocity) +{ + m_velocity = newVelocity; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setBankFamilyId (const int newBankFamilyId) +{ + m_bankFamilyId = newBankFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setBottomFamilyId (const int newBottomFamilyId) +{ + m_bottomFamilyId = newBottomFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setWaterType (TerrainGeneratorWaterType newWaterType) +{ + m_waterType = newWaterType; +} + +//------------------------------------------------------------------- + +bool AffectorRiver::affectsHeight () const +{ + return true; +} + +//------------------------------------------------------------------- + +bool AffectorRiver::affectsShader () const +{ + return true; +} + +//------------------------------------------------------------------- + +unsigned AffectorRiver::getAffectedMaps() const +{ + return + TGM_height + | TGM_shader + | TGM_floraStaticCollidable + | TGM_floraStaticNonCollidable + | TGM_floraDynamicNear + | TGM_floraDynamicFar + ; +} + +//------------------------------------------------------------------- + +void AffectorRiver::createHeightData () +{ + m_heightData.createRiverData (); +} + +//------------------------------------------------------------------- + +void AffectorRiver::prepare () +{ + m_cachedBankFamilyId = -1; + m_cachedBottomFamilyId = -1; +} + +//------------------------------------------------------------------- + +void AffectorRiver::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (generatorChunkData.m_legacyRandomGenerator) + { + _legacyAffect(worldX, worldZ, x, z, amount, generatorChunkData); + return; + } + if (!isEnabled ()) + return; + + if (amount > 0.f) + { + if (m_extent.isWithin (worldX, worldZ)) + { + const float width_2 = m_width * 0.5f; + const float originalHeight = generatorChunkData.heightMap->getData (x, z); + + FindData result; + if (find (Vector2d (worldX, worldZ), width_2, result)) + { + //-- set the height + const float distanceToCenter = fabsf (result.distanceToCenter); + const float desiredHeight = result.height - m_trenchDepth; + const float subWidth = width_2 * m_multiFractal.getValue (result.t); + const float feather = subWidth * (1.f - getFeatherDistance ()); + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + + if (distanceToCenter <= feather) + { + generatorChunkData.heightMap->setData (x, z, desiredHeight); + + //-- set the shader + if (m_cachedBottomFamilyId != m_bottomFamilyId) + { + m_cachedBottomFamilyId = m_bottomFamilyId; + m_cachedBottomSgi = generatorChunkData.shaderGroup->chooseShader (m_bottomFamilyId); + } + + ShaderGroup::Info sgi = m_cachedBottomSgi; + sgi.setChildChoice (randomGenerator.randomFloat()); + generatorChunkData.shaderMap->setData (x, z, sgi); + + //-- clear the flora + generatorChunkData.floraStaticCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraStaticNonCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraDynamicNearMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + generatorChunkData.floraDynamicFarMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + if (distanceToCenter <= subWidth) + { + //-- height + const float t = distanceToCenter / subWidth; + DEBUG_FATAL (t < 0.f || t > 1.f, ("t is out of range")); + + generatorChunkData.heightMap->setData (x, z, linearInterpolate (desiredHeight, originalHeight, sqr (t))); + + if (m_cachedBankFamilyId != m_bankFamilyId) + { + m_cachedBankFamilyId = m_bankFamilyId; + m_cachedBankSgi = generatorChunkData.shaderGroup->chooseShader (m_bankFamilyId); + } + + ShaderGroup::Info sgi = m_cachedBankSgi; + sgi.setChildChoice(randomGenerator.randomFloat()); + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } + } + } + } +} + +void AffectorRiver::_legacyAffect(const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (!isEnabled ()) + return; + + if (amount > 0.f) + { + if (m_extent.isWithin (worldX, worldZ)) + { + const float width_2 = m_width * 0.5f; + const float originalHeight = generatorChunkData.heightMap->getData (x, z); + + FindData result; + if (find (Vector2d (worldX, worldZ), width_2, result)) + { + //-- set the height + const float distanceToCenter = fabsf (result.distanceToCenter); + const float desiredHeight = result.height - m_trenchDepth; + const float subWidth = width_2 * m_multiFractal.getValue (result.t); + const float feather = subWidth * (1.f - getFeatherDistance ()); + + if (distanceToCenter <= feather) + { + generatorChunkData.heightMap->setData (x, z, desiredHeight); + + //-- set the shader + if (m_cachedBottomFamilyId != m_bottomFamilyId) + { + m_cachedBottomFamilyId = m_bottomFamilyId; + m_cachedBottomSgi = generatorChunkData.shaderGroup->chooseShader (m_bottomFamilyId); + } + + ShaderGroup::Info sgi = m_cachedBottomSgi; + sgi.setChildChoice (generatorChunkData.m_legacyRandomGenerator->randomReal (0.0f, 1.0f)); + generatorChunkData.shaderMap->setData (x, z, sgi); + + //-- clear the flora + generatorChunkData.floraStaticCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraStaticNonCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraDynamicNearMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + generatorChunkData.floraDynamicFarMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + if (distanceToCenter <= subWidth) + { + //-- height + const float t = distanceToCenter / subWidth; + DEBUG_FATAL (t < 0.f || t > 1.f, ("t is out of range")); + + generatorChunkData.heightMap->setData (x, z, linearInterpolate (desiredHeight, originalHeight, sqr (t))); + + if (m_cachedBankFamilyId != m_bankFamilyId) + { + m_cachedBankFamilyId = m_bankFamilyId; + m_cachedBankSgi = generatorChunkData.shaderGroup->chooseShader (m_bankFamilyId); + } + + ShaderGroup::Info sgi = m_cachedBankSgi; + sgi.setChildChoice (generatorChunkData.m_legacyRandomGenerator->randomReal (0.0f, 1.0f)); + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorRiver::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + case TAG_0006: + load_0006 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorRiver version %s/%s", buffer, tagBuffer)); + } + break; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (getBankFamilyId ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (getBankFamilyId ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (getBankFamilyId ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + + m_hasLocalWaterTable = iff.read_int32 () != 0; + setLocalWaterTableDepth (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + setLocalWaterTableWidth (getWidth ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + + m_hasLocalWaterTable = iff.read_int32 () != 0; + setLocalWaterTableDepth (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + setLocalWaterTableWidth (getWidth ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + + m_hasLocalWaterTable = iff.read_int32 () != 0; + setLocalWaterTableDepth (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + setLocalWaterTableWidth (getWidth ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + + m_hasLocalWaterTable = iff.read_int32 () != 0; + setLocalWaterTableDepth (iff.read_float ()); + setLocalWaterTableWidth (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +void AffectorRiver::load_0006 (Iff& iff) +{ + iff.enterForm (TAG_0006); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + setWidth (iff.read_float ()); + setBankFamilyId (iff.read_int32 ()); + setBottomFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setTrenchDepth (iff.read_float ()); + setVelocity (iff.read_float ()); + + m_hasLocalWaterTable = iff.read_int32 () != 0; + setLocalWaterTableDepth (iff.read_float ()); + setLocalWaterTableWidth (iff.read_float ()); + setLocalWaterTableShaderSize (iff.read_float ()); + + char* templateName = iff.read_string (); + setLocalWaterTableShaderTemplateName (templateName); + delete [] templateName; + + setWaterType(static_cast (iff.read_int32 ())); + + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0006); +} + +//------------------------------------------------------------------- + +void AffectorRiver::save (Iff& iff) const +{ + iff.insertForm (TAG_0006); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + m_heightData.save (iff); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (m_pointList.getNumberOfElements ()); + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); ++i) + { + iff.insertChunkData (getPoint (i).x); + iff.insertChunkData (getPoint (i).y); + } + + iff.insertChunkData (getWidth ()); + iff.insertChunkData (getBankFamilyId ()); + iff.insertChunkData (getBottomFamilyId ()); + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (getTrenchDepth ()); + iff.insertChunkData (getVelocity ()); + iff.insertChunkData (getHasLocalWaterTable () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getLocalWaterTableDepth ()); + iff.insertChunkData (getLocalWaterTableWidth ()); + iff.insertChunkData (getLocalWaterTableShaderSize ()); + iff.insertChunkString (getLocalWaterTableShaderTemplateName () ? getLocalWaterTableShaderTemplateName () : ""); + iff.insertChunkData (static_cast (getWaterType())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0006); +} + +//------------------------------------------------------------------- + +void AffectorRiver::createWaterTables (ArrayList& waterTableList) const +{ + Vector previousLeftStrip; + Vector previousRightStrip; + const float waterWidth = m_localWaterTableWidth * 0.5f; + + int i; + for (i = 0; i < m_pointList.size () - 1; ++i) + { + // + // setup initial states + // + const bool atStart = i == 0; + const bool atEndNext = i == (m_pointList.size () - 2); + + const Vector2d& currentStart = m_pointList [i]; + const Vector2d& currentEnd = m_pointList [i + 1]; + const Vector2d currentSegment = currentEnd - currentStart; + const Vector2d currentDirection = Vector2d::normalized (currentSegment); + const Vector2d currentNormal = Vector2d::normal (currentDirection, false); + const float currentSegmentLength = currentSegment.magnitude (); + const Vector2d currentStartLeft = currentStart - currentNormal * waterWidth; + const Vector2d currentStartRight = currentStart + currentNormal * waterWidth; + const Vector2d currentEndLeft = currentEnd - currentNormal * waterWidth; + const Vector2d currentEndRight = currentEnd + currentNormal * waterWidth; + + const Vector2d& previousStart = !atStart ? m_pointList [i - 1] : m_pointList [i]; + const Vector2d& previousEnd = !atStart ? m_pointList [i] : m_pointList [i]; + const Vector2d previousSegment = previousEnd - previousStart; + const Vector2d previousDirection = !atStart ? Vector2d::normalized (previousSegment) : currentDirection; + const Vector2d previousNormal = !atStart ? Vector2d::normal (previousDirection, false) : currentNormal; + const float previousSegmentLength = previousSegment.magnitude (); + const Vector2d previousStartLeft = previousStart - previousNormal * waterWidth; + const Vector2d previousStartRight = previousStart + previousNormal * waterWidth; + const Vector2d previousEndLeft = previousEnd - previousNormal * waterWidth; + const Vector2d previousEndRight = previousEnd + previousNormal * waterWidth; + + const Vector2d& nextStart = !atEndNext ? m_pointList [i + 1] : m_pointList [i + 1]; + const Vector2d& nextEnd = !atEndNext ? m_pointList [i + 2] : m_pointList [i + 1]; + const Vector2d nextSegment = nextEnd - nextStart; + const Vector2d nextDirection = !atEndNext ? Vector2d::normalized (nextSegment) : currentDirection; + const Vector2d nextNormal = !atEndNext ? Vector2d::normal (nextDirection, false) : currentNormal; + const float nextSegmentLength = nextSegment.magnitude (); + const Vector2d nextStartLeft = nextStart - nextNormal * waterWidth; + const Vector2d nextStartRight = nextStart + nextNormal * waterWidth; + const Vector2d nextEndLeft = nextEnd - nextNormal * waterWidth; + const Vector2d nextEndRight = nextEnd + nextNormal * waterWidth; + + const Vector2d left [6] = + { + !atStart ? Vector2d::linearInterpolate (previousStartLeft, previousEndLeft, ((previousSegmentLength - waterWidth) / previousSegmentLength)) : currentStartLeft, + !atStart ? currentStart - (Vector2d::normalized (currentStart - (previousEndLeft + currentStartLeft) * 0.5f) * waterWidth) : currentStartLeft, + Vector2d::linearInterpolate (currentStartLeft, currentEndLeft, waterWidth / currentSegmentLength), + Vector2d::linearInterpolate (currentStartLeft, currentEndLeft, ((currentSegmentLength - waterWidth) / currentSegmentLength)), + !atEndNext ? currentEnd - (Vector2d::normalized (currentEnd - (currentEndLeft + nextStartLeft) * 0.5f) * waterWidth) : currentEndLeft, + !atEndNext ? Vector2d::linearInterpolate (nextStartLeft, nextEndLeft, waterWidth / nextSegmentLength) : nextStartLeft + }; + + const Vector2d right [6] = + { + !atStart ? Vector2d::linearInterpolate (previousStartRight, previousEndRight, ((previousSegmentLength - waterWidth) / previousSegmentLength)) : currentStartRight, + !atStart ? currentStart - (Vector2d::normalized (currentStart - (previousEndRight + currentStartRight) * 0.5f) * waterWidth) : currentStartRight, + Vector2d::linearInterpolate (currentStartRight, currentEndRight, waterWidth / currentSegmentLength), + Vector2d::linearInterpolate (currentStartRight, currentEndRight, ((currentSegmentLength - waterWidth) / currentSegmentLength)), + !atEndNext ? currentEnd - (Vector2d::normalized (currentEnd - (currentEndRight + nextStartRight) * 0.5f) * waterWidth) : currentEndRight, + !atEndNext ? Vector2d::linearInterpolate (nextStartRight, nextEndRight, waterWidth / nextSegmentLength) : nextStartRight + }; + + if (!atStart) + { + if (left [0].magnitudeBetweenSquared (left [2]) < right [0].magnitudeBetweenSquared (right [2])) + const_cast (left) [1] = (left [0] + left [2]) * 0.5f; + else + const_cast (right) [1] = (right [0] + right [2]) * 0.5f; + } + + if (!atEndNext) + { + if (left [3].magnitudeBetweenSquared (left [5]) < right [3].magnitudeBetweenSquared (right [5])) + const_cast (left) [4] = (left [3] + left [5]) * 0.5f; + else + const_cast (right) [4] = (right [3] + right [5]) * 0.5f; + } + + // + // walk the current segment + // + { + int j; + for (j = 0; j < m_heightData.getNumberOfPoints (i); ++j) + { + const Vector2d point (m_heightData.getPoint (i, j).x, m_heightData.getPoint (i, j).z); + + Vector2d leftStrip = point - currentNormal * waterWidth; + Vector2d rightStrip = point + currentNormal * waterWidth; + + const float segmentLength = currentStart.magnitudeBetween (point); + + if (segmentLength < waterWidth) + { + const float t = segmentLength / waterWidth; + leftStrip = Vector2d::linearInterpolate (left [1], left [2], t); + rightStrip = Vector2d::linearInterpolate (right [1], right [2], t); + } + else + if (segmentLength > currentSegmentLength - waterWidth) + { + const float t = (segmentLength + waterWidth - currentSegmentLength) / waterWidth; + leftStrip = Vector2d::linearInterpolate (left [3], left [4], t); + rightStrip = Vector2d::linearInterpolate (right [3], right [4], t); + } + + if (j == 0) + { + if (atStart) + { + const Vector2d initialLeft = currentStartLeft - (currentDirection * waterWidth); + const Vector2d initialRight = currentStartRight - (currentDirection * waterWidth); + + AffectorRiver::WaterTable table; + table.points [0].set (initialRight.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, initialRight.y); + table.points [1].set (initialLeft.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, initialLeft.y); + table.points [2].set (leftStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, leftStrip.y); + table.points [3].set (rightStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, rightStrip.y); + table.direction = currentDirection; + waterTableList.add (table); + } + } + else + { + AffectorRiver::WaterTable table; + table.points [0] = previousRightStrip; + table.points [1] = previousLeftStrip; + table.points [2].set (leftStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, leftStrip.y); + table.points [3].set (rightStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, rightStrip.y); + table.direction = currentDirection; + waterTableList.add (table); + } + + previousLeftStrip.set (leftStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, leftStrip.y); + previousRightStrip.set (rightStrip.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, rightStrip.y); + + if (j == m_heightData.getNumberOfPoints (i) - 1) + { + if (atEndNext) + { + const Vector2d finalLeft = currentEndLeft + (currentDirection * waterWidth); + const Vector2d finalRight = currentEndRight + (currentDirection * waterWidth); + + AffectorRiver::WaterTable table; + table.points [0] = previousRightStrip; + table.points [1] = previousLeftStrip; + table.points [2].set (finalLeft.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, finalLeft.y); + table.points [3].set (finalRight.x, m_heightData.getPoint (i, j).y - m_localWaterTableDepth, finalRight.y); + table.direction = currentDirection; + waterTableList.add (table); + } + } + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorRiver::setLocalWaterTableShaderSize (const float newLocalWaterTableShaderSize) +{ + m_localWaterTableShaderSize = newLocalWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setLocalWaterTableShaderTemplateName (const char* newLocalWaterTableShaderTemplateName) +{ + if (m_localWaterTableShaderTemplateName) + { + delete [] m_localWaterTableShaderTemplateName; + m_localWaterTableShaderTemplateName = 0; + } + + if (newLocalWaterTableShaderTemplateName) + m_localWaterTableShaderTemplateName = DuplicateString (newLocalWaterTableShaderTemplateName); +} + +//------------------------------------------------------------------- + +void AffectorRiver::setHasLocalWaterTable (const bool newHasLocalWaterTable) +{ + m_hasLocalWaterTable = newHasLocalWaterTable; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setLocalWaterTableDepth (const float newLocalWaterTableDepth) +{ + m_localWaterTableDepth = newLocalWaterTableDepth; +} + +//------------------------------------------------------------------- + +void AffectorRiver::setLocalWaterTableWidth (const float newLocalWaterTableWidth) +{ + m_localWaterTableWidth = newLocalWaterTableWidth; +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.h new file mode 100644 index 00000000..fc52e17e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRiver.h @@ -0,0 +1,185 @@ +//=================================================================== +// +// AffectorRiver.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_AffectorRiver_H +#define INCLUDED_AffectorRiver_H + +//=================================================================== + +#include "sharedFractal/MultiFractal.h" +#include "sharedTerrain/Affector.h" +#include "sharedMath/Vector2d.h" + +//=================================================================== + +class AffectorRiver : public AffectorBoundaryPoly +{ +public: + + struct WaterTable + { + Vector points [4]; + Vector2d direction; + }; + +public: + + AffectorRiver (); + virtual ~AffectorRiver (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool affectsHeight () const; + virtual bool affectsShader () const; + virtual unsigned getAffectedMaps() const; + virtual void createHeightData (); + + void setTrenchDepth (float newTrenchDepth); + void setVelocity (float newVelocity); + + float getTrenchDepth () const; + float getVelocity () const; + + int getBankFamilyId () const; + void setBankFamilyId (int newBankFamilyId); + int getBottomFamilyId () const; + void setBottomFamilyId (int newBottomFamilyId); + + void createWaterTables (ArrayList& waterTableList) const; + + bool getHasLocalWaterTable () const; + void setHasLocalWaterTable (bool newHasWater); + float getLocalWaterTableShaderSize () const; + void setLocalWaterTableShaderSize (float newLocalWaterTableShaderSize); + const char* getLocalWaterTableShaderTemplateName () const; + void setLocalWaterTableShaderTemplateName (const char* newLocalWaterTableShaderTemplateName); + float getLocalWaterTableDepth () const; + void setLocalWaterTableDepth (float newLocalWaterTableDepth); + float getLocalWaterTableWidth () const; + void setLocalWaterTableWidth (float newLocalWaterTableWidth); + TerrainGeneratorWaterType getWaterType () const; + void setWaterType (TerrainGeneratorWaterType newWaterType); + + +private: + + void _legacyAffect(const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + void load_0006 (Iff& iff); + +private: + + AffectorRiver (const AffectorRiver& rhs); + AffectorRiver& operator= (const AffectorRiver& rhs); + +private: + + mutable int m_cachedBankFamilyId; + mutable ShaderGroup::Info m_cachedBankSgi; + mutable int m_cachedBottomFamilyId; + mutable ShaderGroup::Info m_cachedBottomSgi; + + MultiFractal m_multiFractal; + + //-- accessible + int m_bankFamilyId; + int m_bottomFamilyId; + float m_trenchDepth; + bool m_hasLocalWaterTable; + float m_localWaterTableDepth; + float m_localWaterTableWidth; + float m_localWaterTableShaderSize; + char* m_localWaterTableShaderTemplateName; + float m_velocity; + TerrainGeneratorWaterType m_waterType; + +}; + +//------------------------------------------------------------------- + +inline int AffectorRiver::getBankFamilyId () const +{ + return m_bankFamilyId; +} + +//------------------------------------------------------------------- + +inline int AffectorRiver::getBottomFamilyId () const +{ + return m_bottomFamilyId; +} + +//------------------------------------------------------------------- + +inline float AffectorRiver::getTrenchDepth () const +{ + return m_trenchDepth; +} + +//------------------------------------------------------------------- + +inline float AffectorRiver::getVelocity () const +{ + return m_velocity; +} + +//------------------------------------------------------------------- + +inline float AffectorRiver::getLocalWaterTableShaderSize () const +{ + return m_localWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +inline const char* AffectorRiver::getLocalWaterTableShaderTemplateName () const +{ + return m_localWaterTableShaderTemplateName; +} + +//------------------------------------------------------------------- + +inline bool AffectorRiver::getHasLocalWaterTable () const +{ + return m_hasLocalWaterTable; +} + +//------------------------------------------------------------------- + +inline float AffectorRiver::getLocalWaterTableDepth () const +{ + return m_localWaterTableDepth; +} + +//------------------------------------------------------------------- + +inline float AffectorRiver::getLocalWaterTableWidth () const +{ + return m_localWaterTableWidth; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorWaterType AffectorRiver::getWaterType () const +{ + return m_waterType; +} + + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.cpp new file mode 100644 index 00000000..cb4c1c3e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.cpp @@ -0,0 +1,745 @@ +// +// AffectorRoad.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorRoad.h" + +#include "sharedFile/Iff.h" +#include "sharedMath/Line2d.h" +#include "sharedMath/Vector2d.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/Feather.h" + +//------------------------------------------------------------------- +// +// AffectorRoad +// +AffectorRoad::AffectorRoad () : + AffectorBoundaryPoly (TAG_AROA, TGAT_road), + m_cachedFamilyId (-1), + m_cachedSgi (), + m_familyId (0), + m_featherFunctionShader (TGFF_linear), + m_featherDistanceShader (0.5f), + m_hasFixedHeights(false), + m_heightList () +{ +} + +//------------------------------------------------------------------- + +AffectorRoad::~AffectorRoad () +{ +} + +//------------------------------------------------------------------- + +void AffectorRoad::setFamilyId (const int newFamilyId) +{ + m_familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorRoad::setFeatherFunctionShader (TerrainGeneratorFeatherFunction newFeatherFunction) +{ + m_featherFunctionShader = newFeatherFunction; +} + +//------------------------------------------------------------------- + +void AffectorRoad::setFeatherDistanceShader (const float newFeatherDistance) +{ + m_featherDistanceShader = newFeatherDistance; +} + +//------------------------------------------------------------------- + +void AffectorRoad::setHasFixedHeights (const bool newVal) +{ + m_hasFixedHeights = newVal; +} + +//------------------------------------------------------------------- + +bool AffectorRoad::affectsHeight () const +{ + return true; +} + +//------------------------------------------------------------------- + +bool AffectorRoad::affectsShader () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorRoad::createInitialHeightList () +{ + m_heightList.clear (); + int size = m_pointList.getNumberOfElements (); + for(int i = 0; i < size; i++) + { + m_heightList.add(0.0f); + } +} + +//------------------------------------------------------------------- + +void AffectorRoad::copyHeightList (const ArrayList& newHeightList) +{ + m_heightList = newHeightList; +} + +//------------------------------------------------------------------- + +void AffectorRoad::clearHeightList () +{ + m_heightList.clear (); +} + +//------------------------------------------------------------------- + +unsigned AffectorRoad::getAffectedMaps() const +{ + return + TGM_height + | TGM_shader + | TGM_floraStaticCollidable + | TGM_floraStaticNonCollidable + | TGM_floraDynamicNear + | TGM_floraDynamicFar + ; +} + +//------------------------------------------------------------------- + +void AffectorRoad::createHeightData () +{ + m_heightData.createRoadData (); +} + +//------------------------------------------------------------------- + +void AffectorRoad::prepare () +{ + m_cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +void AffectorRoad::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (generatorChunkData.m_legacyRandomGenerator) + { + _legacyAffect(worldX, worldZ, x, z, amount, generatorChunkData); + return; + } + if (!isEnabled ()) + return; + + if (amount > 0.f) + { + if (m_extent.isWithin (worldX, worldZ)) + { + const float width_2 = m_width * 0.5f; + const float originalHeight = generatorChunkData.heightMap->getData (x, z); + + FindData result; + if (find (Vector2d (worldX, worldZ), width_2, result)) + { + const float distanceToCenter = fabsf (result.distanceToCenter); + const float desiredHeight = result.height; + + if (WithinRangeInclusiveInclusive (0.f, distanceToCenter, width_2 * (1.f - getFeatherDistance ()))) + { + + if(!m_hasFixedHeights) + { + generatorChunkData.heightMap->setData (x, z, desiredHeight); + } + else + { + // ramped road affector using fixed heights + generatorChunkData.heightMap->setData (x,z, getRampedHeight(worldX,worldZ,originalHeight)); + } + + //-- clear the flora + generatorChunkData.floraStaticCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraStaticNonCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraDynamicNearMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + generatorChunkData.floraDynamicFarMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + //-- height + const float t = distanceToCenter / width_2; + DEBUG_FATAL (t < 0.f || t > 1.f, ("t is out of range")); + + if(!m_hasFixedHeights) + { + generatorChunkData.heightMap->setData (x, z, linearInterpolate (desiredHeight, originalHeight, t)); + } + else + { + // ramped road affector using fixed heights + generatorChunkData.heightMap->setData (x, z, getRampedHeight(worldX,worldZ,originalHeight)); + } + + } + + if (WithinRangeInclusiveInclusive (0.f, distanceToCenter, width_2 * (1.f - getFeatherDistanceShader ()))) + { + //-- set the shader + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_familyId); + } + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + + ShaderGroup::Info sgi = m_cachedSgi; + sgi.setChildChoice (randomGenerator.randomFloat()); + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } + } + } +} + +//------------------------------------------------------------------- + +float AffectorRoad::getRampedHeight (const float worldX, const float worldZ,const float terrainHeight) const +{ + if (!m_extent.isWithin (worldX, worldZ)) + return -100.f; + + const float widthSquared = sqr (m_width/2.0f); + + float distanceSquared = widthSquared; + int foundIndex = -1; + + //-- first, scan how far we are from the points + { + const int n = m_pointList.getNumberOfElements (); + int i; + for (i = 0; i < n; ++i) + { + const float x = m_pointList [i].x; + const float y = m_pointList [i].y; + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + { + distanceSquared = thisDistanceSquared; + + foundIndex = i; + } + } + } + + + //-- next, scan each line + { + const int n = m_pointList.getNumberOfElements () - 1; + int i; + for (i = 0; i < n; ++i) + { + const float x1 = m_pointList [i].x; + const float y1 = m_pointList [i].y; //lint !e578 //-- hides y1 (double) + const float x2 = m_pointList [i + 1].x; + const float y2 = m_pointList [i + 1].y; + + const float u = ((worldX - x1) * (x2 - x1) + (worldZ - y1) * (y2 - y1)) / (sqr (x2 - x1) + sqr (y2 - y1)); + if (u >= 0 && u <= 1) + { + const float x = x1 + u * (x2 - x1); + const float y = y1 + u * (y2 - y1); + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + { + distanceSquared = thisDistanceSquared; + foundIndex = i; + } + } + } + } + + if (distanceSquared < widthSquared) + { + + DEBUG_FATAL(foundIndex == -1,("AffectorRoad::getRampedHeight - foundIndex is -1")); + + float height = 0.0f; + + // start feathering + float featherMultiplier = 1.0f; + + const float newFeatherDistance = (m_width/2.0f) * (1.f - getFeatherDistance ()); + + const float newFeatherDistanceSquared = sqr (newFeatherDistance); + + if (distanceSquared >= newFeatherDistanceSquared) + { + featherMultiplier = 1.f - (sqrt (distanceSquared) - newFeatherDistance) / (m_width/2.0f - newFeatherDistance); + const Feather feather(getFeatherFunction()); + featherMultiplier=feather.feather(0.f, 1.f, featherMultiplier); + } + // end feathering + + const float startHeight = m_heightList[foundIndex]; + if(foundIndex != m_pointList.getNumberOfElements() - 1) + { + // project the world point onto the line between the control points and interp for the height + const Vector2d position(worldX,worldZ); + const float endHeight = m_heightList[foundIndex + 1]; + const Vector2d p1(m_pointList [foundIndex].x,m_pointList [foundIndex].y); + const Vector2d p2(m_pointList [foundIndex+1].x,m_pointList [foundIndex+1].y); + const float totalDistance = p1.magnitudeBetween(p2); + + const Line2d line (p1,p2); + const float distToLine = line.computeDistanceTo(position); + const float realDistToPoint1 = p1.magnitudeBetween(position); + const float realDistToPoint2 = p2.magnitudeBetween(position); + const float projectedDistToPoint1 = sqrt(sqr(realDistToPoint1) - sqr(distToLine)); + const float projectedDistToPoint2 = sqrt(sqr(realDistToPoint2) - sqr(distToLine)); + + if(totalDistance != 0.0f && projectedDistToPoint1 <= totalDistance && projectedDistToPoint2 <= totalDistance) + { + height = startHeight + (projectedDistToPoint1/totalDistance) * (endHeight - startHeight); + } + else + { + height = startHeight; + } + } + else + { + height = startHeight; + } + + // don't build canyons or ridges due to feathering to 0 height + const float delta = height - terrainHeight; + height = terrainHeight + (delta * featherMultiplier); + + return height; + } + + return -100.f; +} + + +void AffectorRoad::_legacyAffect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (!isEnabled ()) + return; + + if (amount > 0.f) + { + if (m_extent.isWithin (worldX, worldZ)) + { + const float width_2 = m_width * 0.5f; + const float originalHeight = generatorChunkData.heightMap->getData (x, z); + + FindData result; + if (find (Vector2d (worldX, worldZ), width_2, result)) + { + const float distanceToCenter = fabsf (result.distanceToCenter); + const float desiredHeight = result.height; + + if (WithinRangeInclusiveInclusive (0.f, distanceToCenter, width_2 * (1.f - getFeatherDistance ()))) + { + generatorChunkData.heightMap->setData (x, z, desiredHeight); + + //-- clear the flora + generatorChunkData.floraStaticCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraStaticNonCollidableMap->setData (x, z, generatorChunkData.floraGroup->getDefaultFlora ()); + generatorChunkData.floraDynamicNearMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + generatorChunkData.floraDynamicFarMap->setData (x, z, generatorChunkData.radialGroup->getDefaultRadial ()); + } + else + { + //-- height + const float t = distanceToCenter / width_2; + DEBUG_FATAL (t < 0.f || t > 1.f, ("t is out of range")); + + generatorChunkData.heightMap->setData (x, z, linearInterpolate (desiredHeight, originalHeight, t)); + } + + if (WithinRangeInclusiveInclusive (0.f, distanceToCenter, width_2 * (1.f - getFeatherDistanceShader ()))) + { + //-- set the shader + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_familyId); + } + + ShaderGroup::Info sgi = m_cachedSgi; + sgi.setChildChoice (generatorChunkData.m_legacyRandomGenerator->randomReal (0.0f, 1.0f)); + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorRoad::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + case TAG_0006: + load_0006 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorRoad version %s/%s", buffer, tagBuffer)); + } + break; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + Vector2d newStart; + newStart.x = iff.read_float (); + newStart.y = iff.read_float (); + addPoint (newStart); + + Vector2d newEnd; + newEnd.x = iff.read_float (); + newEnd.y = iff.read_float (); + addPoint (newEnd); + + setWidth (iff.read_float ()); + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + setFeatherFunctionShader (getFeatherFunction ()); + setFeatherDistanceShader (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + setWidth (iff.read_float ()); + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + setFeatherFunctionShader (getFeatherFunction ()); + setFeatherDistanceShader (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + setWidth (iff.read_float ()); + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + setFeatherFunctionShader (static_cast (iff.read_int32 ())); + const float newFeatherDistanceShader = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistanceShader (newFeatherDistanceShader); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +void AffectorRoad::load_0006 (Iff& iff) +{ + iff.enterForm (TAG_0006); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + m_heightData.load (iff); + + iff.enterChunk (TAG_DATA); + + int n = iff.read_int32 (); + int i; + for (i = 0; i < n; ++i) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + addPoint (point); + } + + n = iff.read_int32 (); + for(i = 0; i < n; ++i) + { + m_heightList.add(iff.read_float()); + } + + setWidth (iff.read_float ()); + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + setFeatherFunctionShader (static_cast (iff.read_int32 ())); + const float newFeatherDistanceShader = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistanceShader (newFeatherDistanceShader); + setHasFixedHeights(iff.read_int32() != 0); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0006); +} + +//------------------------------------------------------------------- + +void AffectorRoad::save (Iff& iff) const +{ + iff.insertForm (TAG_0006); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + m_heightData.save (iff); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (m_pointList.getNumberOfElements ()); + int i; + for (i = 0; i < m_pointList.getNumberOfElements (); ++i) + { + iff.insertChunkData (getPoint (i).x); + iff.insertChunkData (getPoint (i).y); + } + + iff.insertChunkData (m_heightList.getNumberOfElements ()); + for (i = 0; i < m_heightList.getNumberOfElements (); ++i) + { + iff.insertChunkData (m_heightList[i]); + } + + iff.insertChunkData (getWidth ()); + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (static_cast (getFeatherFunctionShader ())); + iff.insertChunkData (getFeatherDistanceShader ()); + iff.insertChunkData (m_hasFixedHeights ? static_cast (1) : static_cast (0)); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0006); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.h new file mode 100644 index 00000000..97df7742 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorRoad.h @@ -0,0 +1,120 @@ +//=================================================================== +// +// AffectorRoad.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//=================================================================== + +#ifndef INCLUDED_AffectorRoad_H +#define INCLUDED_AffectorRoad_H + +//=================================================================== + +#include "sharedTerrain/Affector.h" + +//=================================================================== + +class AffectorRoad : public AffectorBoundaryPoly +{ +public: + + AffectorRoad (); + virtual ~AffectorRoad (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool affectsHeight () const; + virtual bool affectsShader () const; + virtual unsigned getAffectedMaps() const; + virtual void createHeightData (); + + int getFamilyId () const; + void setFamilyId (int newFamilyId); + + TerrainGeneratorFeatherFunction getFeatherFunctionShader () const; + void setFeatherFunctionShader (TerrainGeneratorFeatherFunction newFeatherFunction); + float getFeatherDistanceShader () const; + void setFeatherDistanceShader (float newFeatherDistance); + + float getRampedHeight (const float worldX, const float worldZ,const float terrainHeight) const; + + bool getHasFixedHeights() const; + void setHasFixedHeights(const bool newVal); + void createInitialHeightList (); + void clearHeightList (); + const ArrayList& getHeightList () const; + void copyHeightList (const ArrayList& newHeightList); + +private: + + void _legacyAffect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + void load_0006 (Iff& iff); + +private: + + AffectorRoad (const AffectorRoad& rhs); + AffectorRoad& operator= (const AffectorRoad& rhs); + +private: + + mutable int m_cachedFamilyId; + mutable ShaderGroup::Info m_cachedSgi; + + //-- accessible + int m_familyId; + TerrainGeneratorFeatherFunction m_featherFunctionShader; + float m_featherDistanceShader; + bool m_hasFixedHeights; + ArrayList m_heightList; +}; + +//------------------------------------------------------------------- + +inline int AffectorRoad::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorFeatherFunction AffectorRoad::getFeatherFunctionShader () const +{ + return m_featherFunctionShader; +} + +//------------------------------------------------------------------- + +inline float AffectorRoad::getFeatherDistanceShader () const +{ + return m_featherDistanceShader; +} + +//------------------------------------------------------------------- + +inline bool AffectorRoad::getHasFixedHeights () const +{ + return m_hasFixedHeights; +} + +//------------------------------------------------------------------- + +inline const ArrayList& AffectorRoad::getHeightList () const +{ + return m_heightList; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.cpp new file mode 100644 index 00000000..2c8f2500 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.cpp @@ -0,0 +1,431 @@ +// +// AffectorShader.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/AffectorShader.h" + +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" +#include "sharedFile/Iff.h" + +//------------------------------------------------------------------- +// +// AffectorShaderConstant +// +AffectorShaderConstant::AffectorShaderConstant () : + TerrainGenerator::Affector (TAG_ASCN, TGAT_shaderConstant), + m_cachedFamilyId (-1), + m_cachedSgi (), + m_cachedFeatherClamp (0.f), + m_familyId (0), + m_useFeatherClampOverride (false), + m_featherClampOverride (1.f) +{ +} + +//------------------------------------------------------------------- + +AffectorShaderConstant::~AffectorShaderConstant () +{ +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::setFamilyId (const int familyId) +{ + m_familyId = familyId; +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::setUseFeatherClampOverride (const bool useFeatherClampOverride) +{ + m_useFeatherClampOverride = useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::setFeatherClampOverride (const float featherClampOverride) +{ + m_featherClampOverride = featherClampOverride; +} + +//------------------------------------------------------------------- + +bool AffectorShaderConstant::affectsShader () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::prepare () +{ + m_cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +unsigned AffectorShaderConstant::getAffectedMaps() const +{ + return TGM_shader; +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::affect (const float worldX, const float worldZ, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (generatorChunkData.m_legacyRandomGenerator) + { + _legacyAffect(worldX, worldZ, x, z, amount, generatorChunkData); + return; + } + if (amount > 0.f) + { + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_familyId); + m_cachedFeatherClamp = generatorChunkData.shaderGroup->getFamilyFeatherClamp (m_familyId); + } + + const float featherClamp = m_useFeatherClampOverride ? m_featherClampOverride : m_cachedFeatherClamp; + + FastRandomGenerator randomGenerator(CoordinateHash::hashTuple(worldX, worldZ)); + +#if 1 + if (amount >= featherClamp) +#else + //-- this causes better looking terrain, but more shader blends + if (randomGenerator.randomFloat() <= amount * featherClamp) +#endif + { + ShaderGroup::Info sgi = m_cachedSgi; + sgi.setChildChoice(randomGenerator.randomFloat()); + + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } +} + +void AffectorShaderConstant::_legacyAffect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_familyId); + m_cachedFeatherClamp = generatorChunkData.shaderGroup->getFamilyFeatherClamp (m_familyId); + } + + const float featherClamp = m_useFeatherClampOverride ? m_featherClampOverride : m_cachedFeatherClamp; + +#if 1 + if (amount >= featherClamp) +#else + //-- this causes better looking terrain, but more shader blends + if (generatorChunkData.randomGenerator.randomReal (0.f, 1.f) <= amount * featherClamp) +#endif + { + ShaderGroup::Info sgi = m_cachedSgi; + sgi.setChildChoice (generatorChunkData.m_legacyRandomGenerator->randomReal (0.0f, 1.0f)); + + generatorChunkData.shaderMap->setData (x, z, sgi); + } + } +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorShaderConstant version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFamilyId (iff.read_int32 ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFamilyId (iff.read_int32 ()); + setUseFeatherClampOverride (iff.read_int32 () != 0); + setFeatherClampOverride (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorShaderConstant::save (Iff& iff) const +{ + iff.insertForm (TAG_0001); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (getUseFeatherClampOverride () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getFeatherClampOverride ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- +// +// AffectorShaderReplace +// +AffectorShaderReplace::AffectorShaderReplace () : + TerrainGenerator::Affector (TAG_ASRP, TGAT_shaderReplace), + m_cachedFamilyId (-1), + m_cachedSgi (), + m_cachedFeatherClamp (0.f), + m_sourceFamilyId (0), + m_destinationFamilyId (0), + m_useFeatherClampOverride (false), + m_featherClampOverride (1.f) +{ +} + +//------------------------------------------------------------------- + +AffectorShaderReplace::~AffectorShaderReplace () +{ +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::setSourceFamilyId (const int sourceFamilyId) +{ + m_sourceFamilyId = sourceFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::setDestinationFamilyId (const int destinationFamilyId) +{ + m_destinationFamilyId = destinationFamilyId; +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::setUseFeatherClampOverride (const bool useFeatherClampOverride) +{ + m_useFeatherClampOverride = useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::setFeatherClampOverride (const float featherClampOverride) +{ + m_featherClampOverride = featherClampOverride; +} + +//------------------------------------------------------------------- + +bool AffectorShaderReplace::affectsShader () const +{ + return true; +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::prepare () +{ + m_cachedFamilyId = -1; +} + +//------------------------------------------------------------------- + +unsigned AffectorShaderReplace::getAffectedMaps() const +{ + return TGM_shader; +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::affect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (amount > 0.f) + { + const ShaderGroup::Info sgi = generatorChunkData.shaderMap->getData (x, z); + + if (sgi.getFamilyId () == m_sourceFamilyId) + { + if (m_cachedFamilyId != m_destinationFamilyId) + { + m_cachedFamilyId = m_destinationFamilyId; + m_cachedSgi = generatorChunkData.shaderGroup->chooseShader (m_destinationFamilyId); + m_cachedFeatherClamp = generatorChunkData.shaderGroup->getFamilyFeatherClamp (m_destinationFamilyId); + } + + const float featherClamp = m_useFeatherClampOverride ? m_featherClampOverride : m_cachedFeatherClamp; + +#if 1 + if (amount >= featherClamp) +#else + //-- this causes better looking terrain, but more shader blends + if (generatorChunkData.randomGenerator.randomReal (0.f, 1.f) <= amount * featherClamp) +#endif + { + m_cachedSgi.setChildChoice (sgi.getChildChoice ()); + + generatorChunkData.shaderMap->setData (x, z, m_cachedSgi); + } + } + } +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("invalid AffectorShaderReplace version %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setSourceFamilyId (iff.read_int32 ()); + setDestinationFamilyId (iff.read_int32 ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setSourceFamilyId (iff.read_int32 ()); + setDestinationFamilyId (iff.read_int32 ()); + setUseFeatherClampOverride (iff.read_int32 () != 0); + setFeatherClampOverride (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void AffectorShaderReplace::save (Iff& iff) const +{ + iff.insertForm (TAG_0001); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (getSourceFamilyId ()); + iff.insertChunkData (getDestinationFamilyId ()); + iff.insertChunkData (getUseFeatherClampOverride () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getFeatherClampOverride ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.h b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.h new file mode 100644 index 00000000..e2c91336 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/AffectorShader.h @@ -0,0 +1,168 @@ +//=================================================================== +// +// AffectorShader.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//=================================================================== + +#ifndef INCLUDED_AffectorShader_H +#define INCLUDED_AffectorShader_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class AffectorShaderConstant : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable int m_cachedFamilyId; + mutable ShaderGroup::Info m_cachedSgi; + mutable float m_cachedFeatherClamp; + + //-- accessible + int m_familyId; + bool m_useFeatherClampOverride; + float m_featherClampOverride; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + +private: + + AffectorShaderConstant (const AffectorShaderConstant& rhs); + AffectorShaderConstant& operator= (const AffectorShaderConstant& rhs); + + void _legacyAffect (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + +public: + + AffectorShaderConstant (); + virtual ~AffectorShaderConstant (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool affectsShader () const; + virtual unsigned getAffectedMaps() const; + + int getFamilyId () const; + void setFamilyId (int newFamilyId); + + bool getUseFeatherClampOverride () const; + void setUseFeatherClampOverride (bool useFeatherClampOverride); + float getFeatherClampOverride () const; + void setFeatherClampOverride (float featherClampOverride); +}; + +//------------------------------------------------------------------- + +inline int AffectorShaderConstant::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline bool AffectorShaderConstant::getUseFeatherClampOverride () const +{ + return m_useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +inline float AffectorShaderConstant::getFeatherClampOverride () const +{ + return m_featherClampOverride; +} + +//=================================================================== + +class AffectorShaderReplace : public TerrainGenerator::Affector +{ +private: + + //-- not accessible + mutable int m_cachedFamilyId; + mutable ShaderGroup::Info m_cachedSgi; + mutable float m_cachedFeatherClamp; + + //-- accessible + int m_sourceFamilyId; + int m_destinationFamilyId; + bool m_useFeatherClampOverride; + float m_featherClampOverride; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + +private: + + AffectorShaderReplace (const AffectorShaderReplace& rhs); + AffectorShaderReplace& operator= (const AffectorShaderReplace& rhs); + +public: + + AffectorShaderReplace (); + virtual ~AffectorShaderReplace (); + + virtual void prepare (); + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool affectsShader () const; + virtual unsigned getAffectedMaps() const; + + int getSourceFamilyId () const; + void setSourceFamilyId (int newSourceFamilyId); + int getDestinationFamilyId () const; + void setDestinationFamilyId (int newDestinationFamilyId); + + bool getUseFeatherClampOverride () const; + void setUseFeatherClampOverride (bool useFeatherClampOverride); + float getFeatherClampOverride () const; + void setFeatherClampOverride (float featherClampOverride); +}; + +//------------------------------------------------------------------- + +inline int AffectorShaderReplace::getSourceFamilyId () const +{ + return m_sourceFamilyId; +} + +//------------------------------------------------------------------- + +inline int AffectorShaderReplace::getDestinationFamilyId () const +{ + return m_destinationFamilyId; +} + +//------------------------------------------------------------------- + +inline bool AffectorShaderReplace::getUseFeatherClampOverride () const +{ + return m_useFeatherClampOverride; +} + +//------------------------------------------------------------------- + +inline float AffectorShaderReplace::getFeatherClampOverride () const +{ + return m_featherClampOverride; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Array2d.h b/engine/shared/library/sharedTerrain/src/shared/generator/Array2d.h new file mode 100644 index 00000000..4d33d80e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Array2d.h @@ -0,0 +1,238 @@ +//=================================================================== +// +// Array2d.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//-- +// +// Array2d abstracts a 2d array of values. When accessing an entry +// in the 2d array, if you specify an out-of-bounds entry, the coordinate +// will clamp +// +//=================================================================== + +#ifndef INCLUDED_Array2d_H +#define INCLUDED_Array2d_H + +//=================================================================== + +template +class Array2d +{ +private: + + int width; + int height; + + T* data; + +private: + + void deallocate (); + +private: + + Array2d (const Array2d& rhs); + Array2d& operator= (const Array2d& rhs); + +public: + + Array2d (); + ~Array2d (); + + int getWidth () const; + int getHeight () const; + bool isEmpty () const; + void allocate (int width, int height); + void allocateAndSet (int width, int height, const T* newData); + void makeZero (); + void makeValue (const T& newValue); + void makeCopy (const Array2d& rhs); + + const T* getData () const; + + const T& getData (int x, int z) const; + T& getData (int x, int z); + + void setData (int x, int z, const T& newData); +}; + +//=================================================================== + +template +Array2d::Array2d () : + width (0), + height (0), + data (0) +{ +} + +//------------------------------------------------------------------- + +template +Array2d::~Array2d () +{ + width = height = 0; + + deallocate (); +} //lint !e1740 // pointer member data not freed + +//------------------------------------------------------------------- + +template +int Array2d::getWidth () const +{ + return width; +} + +//------------------------------------------------------------------- + +template +int Array2d::getHeight () const +{ + return height; +} + +//------------------------------------------------------------------- + +template +bool Array2d::isEmpty () const +{ + return width == 0 || height == 0; +} + +//------------------------------------------------------------------- + +template +void Array2d::deallocate () +{ + if (data) + { + delete [] data; + data = 0; + } +} + +//------------------------------------------------------------------- + +template +void Array2d::allocate (int newWidth, int newHeight) +{ + DEBUG_FATAL (newWidth <= 0, ("newWidth <= 0")); + DEBUG_FATAL (newHeight <= 0, ("newHeight <= 0")); + + if (newWidth > width || newHeight > height) + { + deallocate (); + + width = newWidth; + height = newHeight; + + data = new T [newWidth * newHeight]; //lint !e737 //-- sizeof + } +} + +//------------------------------------------------------------------- + +template +void Array2d::allocateAndSet (int newWidth, int newHeight, const T* newData) +{ + NOT_NULL (newData); + + allocate (newWidth, newHeight); + NOT_NULL (data); + + memcpy (data, newData, width * height * sizeof (T)); //lint !e737 //-- sizeof +} + +//------------------------------------------------------------------- + +template +const T* Array2d::getData () const +{ + return data; +} + +//------------------------------------------------------------------- + +template +const T& Array2d::getData (int x, int z) const +{ + NOT_NULL (data); + DEBUG_FATAL (isEmpty (), ("Array2d is empty")); + DEBUG_FATAL (x < 0 || x >= width, ("x is out of range")); + DEBUG_FATAL (z < 0 || z >= height, ("z is out of range")); + + return data [z * width + x]; +} + +//------------------------------------------------------------------- + +template +T& Array2d::getData (int x, int z) +{ + NOT_NULL (data); + DEBUG_FATAL (isEmpty (), ("Array2d is empty")); + DEBUG_FATAL (x < 0 || x >= width, ("x is out of range")); + DEBUG_FATAL (z < 0 || z >= height, ("z is out of range")); + + return data [z * width + x]; +} + +//------------------------------------------------------------------- + +template +void Array2d::setData (int x, int z, const T& newData) +{ + NOT_NULL (data); + DEBUG_FATAL (isEmpty (), ("Array2d is empty")); + DEBUG_FATAL (x < 0 || x >= width, ("x is out of range")); + DEBUG_FATAL (z < 0 || z >= height, ("z is out of range")); + + data [z * width + x] = newData; +} + +//------------------------------------------------------------------- + +template +void Array2d::makeZero () +{ + NOT_NULL (data); + DEBUG_FATAL (isEmpty (), ("Array2d is empty")); + + memset (data, 0, width * height * sizeof (T)); //lint !e737 //-- sizeof +} + +//------------------------------------------------------------------- + +template +void Array2d::makeValue (const T& newValue) +{ + NOT_NULL (data); + DEBUG_FATAL (isEmpty (), ("Array2d is empty")); + + int i; + int j; + for (j = 0; j < height; j++) + for (i = 0; i < width; i++) + data [j * width + i] = newValue; +} + +//------------------------------------------------------------------- + +template +void Array2d::makeCopy (const Array2d& rhs) +{ + DEBUG_FATAL (width != rhs.getWidth (), ("width (%i) != rhs.getWidth (%i)", width, rhs.getWidth ())); + DEBUG_FATAL (height != rhs.getHeight (), ("height (%i) != rhs.getHeight (%i)", height, rhs.getHeight ())); + NOT_NULL (data); + NOT_NULL (rhs.data); + + memcpy (data, rhs.data, width * height * sizeof (T)); //lint !e737 //-- sizeof +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.cpp new file mode 100644 index 00000000..e9215147 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.cpp @@ -0,0 +1,611 @@ +//=================================================================== +// +// BitmapGroup.cpp +// +// copyright 2004, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/BitmapGroup.h" + +#include "sharedFile/Iff.h" +#include "sharedImage/Image.h" +#include "sharedImage/ImageFormatList.h" + +#include +#include +#include + +//=================================================================== + +namespace +{ + const Tag TAG_MGRP = TAG (M,G,R,P); + const Tag TAG_MFAM = TAG (M,F,A,M); +} + +//=================================================================== +// +// BitmapGroup::Family +// +class BitmapGroup::Family +{ +public: + + explicit Family (int familyId); + ~Family (); + + const char* getName () const; + void setName (const char* name); + void setBitmapName (const char* name); + const char* getBitmapName() const; + + int getFamilyId () const; + void setFamilyId (int familyId); + + const Image& getBitmap () const; + Image& getBitmap (); + void loadBitmap(const char* bitmapName); + void loadBitmapByFilename(); + void setBitmap(const Image* image); + +private: + + Family (); + Family (const Family& rhs); + Family& operator= (const Family& rhs); + +private: + + char* m_name; + char* m_bitmapName; + int m_familyId; + Image* m_bitmap; +}; + +//------------------------------------------------------------------- + +BitmapGroup::Family::Family (int familyId) : + m_name (0), + m_bitmapName (0), + m_familyId (familyId), + m_bitmap(0) +{ + + +} + +//------------------------------------------------------------------- + +BitmapGroup::Family::~Family () +{ + if(m_name) + { + delete [] m_name; + m_name = 0; + } + if(m_bitmapName) + { + delete [] m_bitmapName; + m_bitmapName = 0; + } + if(m_bitmap) + { + delete m_bitmap; + m_bitmap = 0; + } +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::loadBitmap(const char* bitmapName) +{ + if(m_bitmap) + { + delete m_bitmap; + m_bitmap = 0; + } + + bool valid = false; + char name[256]; + + sprintf(name,"terrain/%s.tga",bitmapName); + m_bitmap = ImageFormatList::loadImage (name); + + if (!m_bitmap) + { + DEBUG_WARNING (true, ("BitmapGroup::Family::loadBitmap - invalid image (%s)",name)); + } + else + { + if(!(m_bitmap->getPixelFormat() == Image::PF_w_8)) + { + DEBUG_WARNING (true, ("BitmapGroup::Family::loadBitmap %s - m_bitmap->getPixelFormat() returned %d - should be Image::PF_w_8",name,m_bitmap->getPixelFormat())); + } + else + { + valid = true; + } + } + + if (!valid) + { + delete m_bitmap; + m_bitmap = 0; + } + else + { + setBitmapName(name); + } +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::loadBitmapByFilename() +{ + + if(m_bitmap) + { + delete m_bitmap; + m_bitmap = 0; + } + + bool valid = false; + + m_bitmap = ImageFormatList::loadImage (this->m_bitmapName); + + if (!m_bitmap) + { + if(!m_bitmapName) + { + DEBUG_WARNING (true, ("BitmapGroup::Family::loadBitmapByFilename() - invalid image - m_bitmapName is NULL")); + } + else + { + DEBUG_WARNING (true, ("BitmapGroup::Family::loadBitmapByFilename() - invalid image - %s",m_bitmapName)); + } + + } + else + { + if(!(m_bitmap->getPixelFormat() == Image::PF_w_8)) + { + DEBUG_WARNING (true, ("BitmapGroup::Family::loadBitmapByFilename() %s - m_bitmap->getPixelFormat() returned %d - should be Image::PF_w_8",this->m_bitmapName,m_bitmap->getPixelFormat())); + } + else + { + valid = true; + } + } + + if (!valid) + { + delete m_bitmap; + m_bitmap = 0; + } + + +} + +//------------------------------------------------------------------- + +const char* BitmapGroup::Family::getName () const +{ + return m_name; +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::setName (const char* name) +{ + if (m_name) + { + delete [] m_name; + m_name = 0; + } + + if (name) + m_name = DuplicateString (name); +} + +//------------------------------------------------------------------- + +const char* BitmapGroup::Family::getBitmapName() const +{ + return m_bitmapName; +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::setBitmapName (const char* name) +{ + if (m_bitmapName) + { + delete [] m_bitmapName; + m_bitmapName = 0; + } + + if (name) + { + m_bitmapName = DuplicateString (name); + } +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::setBitmap(const Image* image) +{ + if(m_bitmap) + { + delete m_bitmap; + m_bitmap = 0; + } + m_bitmap = (Image*)image; +} + +int BitmapGroup::Family::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void BitmapGroup::Family::setFamilyId (int familyId) +{ + m_familyId = familyId; +} + +//------------------------------------------------------------------- + +const Image& BitmapGroup::Family::getBitmap () const +{ + return *m_bitmap; +} + +//------------------------------------------------------------------- + +Image& BitmapGroup::Family::getBitmap () +{ + return *m_bitmap; +} + + +BitmapGroup::BitmapGroup () : + m_familyMap (new FamilyMap) +{ +} + +//------------------------------------------------------------------- + +BitmapGroup::~BitmapGroup () +{ + //-- delete family list + reset (); + + delete m_familyMap; + m_familyMap = 0; +} + +//------------------------------------------------------------------- + +void BitmapGroup::load (Iff& iff) +{ + //-- delete family list first + reset (); + + //-- load data + if (iff.enterForm (TAG_MGRP, true)) + { + DEBUG_WARNING (iff.getCurrentName () != TAG_0000, ("BitmapGroup::load - loading old version")); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + DEBUG_FATAL (true, ("BitmapGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void BitmapGroup::save (Iff& iff) const +{ + iff.insertForm (TAG_MGRP); + + iff.insertForm (TAG_0000); + + for (FamilyMap::iterator iter = m_familyMap->begin (); iter != m_familyMap->end (); ++iter) + { + const Family* family = iter->second; + + iff.insertForm (TAG_MFAM); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + iff.insertChunkString (family->getBitmapName()); + + iff.exitChunk (); + + iff.exitForm (); + } + + iff.exitForm (); + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void BitmapGroup::reset () +{ + for (FamilyMap::iterator iter = m_familyMap->begin (); iter != m_familyMap->end (); ++iter) + delete iter->second; + + m_familyMap->clear (); +} + +//------------------------------------------------------------------- + +const char* BitmapGroup::getFamilyName (int familyId) const +{ + const Family* const family = getFamily (familyId); + return family->getName (); +} + +//------------------------------------------------------------------- + +void BitmapGroup::setFamilyName (int familyId, const char* name) +{ + Family* const family = getFamily (familyId); + family->setName (name); +} + +void BitmapGroup::loadFamilyBitmap(int familyId, const char* bitmapName) +{ + Family* const family = getFamily(familyId); + family->loadBitmap(bitmapName); +} + +//------------------------------------------------------------------- + +const Image* BitmapGroup::getFamilyBitmap (int familyId) const +{ + const Family* const family = getFamily (familyId); + return &family->getBitmap (); +} + +//------------------------------------------------------------------- + +Image* BitmapGroup::getFamilyBitmap (int familyId) +{ + + Family* const family = getFamily (familyId); + return &family->getBitmap (); +} + +//------------------------------------------------------------------- + +void BitmapGroup::reloadAllFamilyBitmaps() +{ + int i; + for(i = 0; i < getNumberOfFamilies(); ++i) + { + const int id = getFamilyId(i); + Family* const family = getFamily(id); + NOT_NULL (family); + family->loadBitmapByFilename(); + } +} + +//------------------------------------------------------------------- + +void BitmapGroup::addFamily (int familyId, const char* name, const char* bitmapName) +{ + DEBUG_FATAL (getFamily (familyId) != 0, ("family with id %i already exists", familyId)); + + Family* family = new Family (familyId); + family->setName (name); + family->setBitmapName(bitmapName); + + IGNORE_RETURN (m_familyMap->insert (FamilyMap::value_type (familyId, family))); +} + +//------------------------------------------------------------------- + +void BitmapGroup::removeFamily (int familyId) +{ + FamilyMap::iterator iter = m_familyMap->find (familyId); + DEBUG_FATAL (iter == m_familyMap->end (), ("family with id %i not found", familyId)); + + Family* family = iter->second; + delete family; + m_familyMap->erase (iter); +} + +//------------------------------------------------------------------- + +bool BitmapGroup::hasFamily (int familyId) const +{ + return getFamily (familyId) != 0; +} + +//------------------------------------------------------------------- + +bool BitmapGroup::findFamily (const char* name, int& familyId) const +{ + const Family* const family = getFamily (name); + + if (family) + familyId = family->getFamilyId (); + + return family != 0; +} + +//------------------------------------------------------------------- + +int BitmapGroup::getNumberOfFamilies () const +{ + return static_cast (m_familyMap->size ()); +} + +//------------------------------------------------------------------- + +const BitmapGroup::Family* BitmapGroup::getFamily (int familyId) const +{ + FamilyMap::const_iterator iter = m_familyMap->find (familyId); + if (iter != m_familyMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +BitmapGroup::Family* BitmapGroup::getFamily (int familyId) +{ + FamilyMap::iterator iter = m_familyMap->find (familyId); + if (iter != m_familyMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +const BitmapGroup::Family* BitmapGroup::getFamily (const char* familyName) const +{ + FamilyMap::iterator iter = m_familyMap->begin (); + for (; iter != m_familyMap->end (); ++iter) + { + const Family* const family = iter->second; + + if (_stricmp (familyName, family->getName ()) == 0) + return family; + } + + return 0; +} + +//------------------------------------------------------------------- + +BitmapGroup::Family* BitmapGroup::getFamily (const char* familyName) +{ + FamilyMap::iterator iter = m_familyMap->begin (); + for (; iter != m_familyMap->end (); ++iter) + { + Family* const family = iter->second; + + if (_stricmp (familyName, family->getName ()) == 0) + return family; + } + + return 0; +} + +//------------------------------------------------------------------- + +void BitmapGroup::setFamilyId (int familyIndex, int familyId) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, familyIndex, getNumberOfFamilies ()); + + Family* const family = getFamily (familyIndex); + NOT_NULL (family); + family->setFamilyId (familyId); +} + +//------------------------------------------------------------------- + +void BitmapGroup::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG_MFAM); + + iff.enterChunk (TAG_DATA); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (getFamily (familyId) != 0, ("BitmapGroup::load familyId %i is already in use", familyId)); + + char* nameBuffer = iff.read_string (); + char* bitmapNameBuffer = iff.read_string(); + + //-- add family + addFamily (familyId, nameBuffer, bitmapNameBuffer); + Family* const family = getFamily(familyId); + NOT_NULL (family); + family->loadBitmapByFilename(); + delete [] nameBuffer; + delete [] bitmapNameBuffer; + + iff.exitChunk (); + + + + iff.exitForm (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +int BitmapGroup::getFamilyId (int familyIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, familyIndex, static_cast (m_familyMap->size ())); + + FamilyMap::iterator iter = m_familyMap->begin (); + int i = 0; + for (; i < familyIndex || iter == m_familyMap->end (); ++i, ++iter) + ; + + DEBUG_FATAL (iter == m_familyMap->end (), ("")); + return iter->second->getFamilyId (); +} + + +//------------------------------------------------------------------- + +int BitmapGroup::createUniqueFamilyId () const +{ + int familyId = 1; + + while (getFamily (familyId) != 0) + ++familyId; + + return familyId; +} + +//------------------------------------------------------------------- + +std::string BitmapGroup::createUniqueFamilyName (const char* baseName) const +{ + char familyName [1000]; + int i = 0; + + do + { + ++i; + + sprintf (familyName, "%s_%i", baseName, i); + } + while (getFamily (familyName) != 0); + + return std::string (familyName); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.h new file mode 100644 index 00000000..bbfeaadc --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/BitmapGroup.h @@ -0,0 +1,78 @@ +//=================================================================== +// +// BitmapGroup.h +// +// copyright 2004, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_BitmapGroup_H +#define INCLUDED_BitmapGroup_H + +//=================================================================== + +class Iff; +class Image; +//=================================================================== + +class BitmapGroup +{ +public: + + BitmapGroup (); + ~BitmapGroup (); + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void reset (); + + void prepare (int cacheX, int cacheY); + + //-- + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + void loadFamilyBitmap(int familyId, const char* name); + const Image* getFamilyBitmap (int familyId) const; + Image* getFamilyBitmap (int familyId); + void reloadAllFamilyBitmaps(); // reloads all the bitmaps - called from the terrain editor + + //-- family id routines + void addFamily (int familyId, const char* name, const char* bitmapName); + void removeFamily (int familyId); + bool hasFamily (int familyId) const; + bool findFamily (const char* name, int& familyId) const; + + //-- family index routines + int getNumberOfFamilies () const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); + +private: + + //-- list of families + class Family; + typedef stdmap::fwd FamilyMap; + FamilyMap* m_familyMap; + +private: + + const Family* getFamily (int familyId) const; + Family* getFamily (int familyId); + const Family* getFamily (const char* familyName) const; + Family* getFamily (const char* familyName); + + int createUniqueFamilyId () const; + std::string createUniqueFamilyName (const char* baseName) const; + + void load_0000 (Iff& iff); + +private: + + BitmapGroup (const BitmapGroup& rhs); + BitmapGroup& operator= (const BitmapGroup& rhs); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.cpp new file mode 100644 index 00000000..a97de537 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.cpp @@ -0,0 +1,1903 @@ +// +// Boundary.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/Boundary.h" +#include "sharedTerrain/Feather.h" + +#include "sharedFile/Iff.h" +#include "sharedMath/Vector2d.h" + +#include + +//------------------------------------------------------------------- +// +// BoundaryCircle +// +BoundaryCircle::BoundaryCircle () : + TerrainGenerator::Boundary (TAG_BCIR, TGBT_circle), + centerX (0), + centerZ (0), + radius (0), + radiusSquared (0) +{ +} + +//------------------------------------------------------------------- + +BoundaryCircle::~BoundaryCircle () +{ +} + +//------------------------------------------------------------------- + +const Vector2d BoundaryCircle::getCenter () const +{ + return Vector2d (centerX, centerZ); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::setCircle (const float newCenterX, const float newCenterZ, const float newRadius) +{ + centerX = newCenterX; + centerZ = newCenterZ; + radius = static_cast (fabs (newRadius)); + radiusSquared = sqr (radius); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::translate (const Vector2d& translation) +{ + centerX += translation.x; + centerZ += translation.y; +} + +//------------------------------------------------------------------- + +void BoundaryCircle::scale (const float scalar) +{ + radius *= scalar; + radiusSquared = sqr (radius); +} + +//------------------------------------------------------------------- + +bool BoundaryCircle::intersects(const Rectangle2d& other) const +{ + Rectangle2d rect(centerX-radius, centerZ-radius, centerX+radius, centerZ+radius); + return rect.intersects(other); +} + +//------------------------------------------------------------------- + +float BoundaryCircle::isWithin (const float worldX, const float worldZ) const +{ + const float distanceSquared = sqr (centerX - worldX) + sqr (centerZ - worldZ); + + if (distanceSquared > radiusSquared) + return 0.f; + + //-- calculate feathering + const float innerRadiusSquared = sqr (radius * (1 - getFeatherDistance ())); + + if (distanceSquared <= innerRadiusSquared) + return 1.f; + + return 1.f - ((distanceSquared - innerRadiusSquared) / (radiusSquared - innerRadiusSquared)); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const +{ + if (!intersects(scanArea)) + { + return; + } + + const float real2Sample = float(numberOfPoles-1) / (scanArea.y1 - scanArea.y0); + + // transform circle relative to scanArea. + float cx = centerX - scanArea.x0; + float cz = centerZ - scanArea.y0; + + // scale circle to sample area + cx *= real2Sample; + cz *= real2Sample; + const float r = radius * real2Sample; + + const int zmin = std::max(0, int(ceil(cz-r))); + const int zmax = std::min(numberOfPoles-1, int(floor(cz+r))); + if (zmaxdestRow[x]) + { + destRow[x]=amount; + } + } + } + } +} + +//------------------------------------------------------------------- + +void BoundaryCircle::expand (Rectangle2d& extent) const +{ + extent.expand (centerX - radius, centerZ - radius); + extent.expand (centerX + radius, centerZ + radius); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::setCenter (const Vector2d& center) +{ + translate (center - getCenter ()); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void BoundaryCircle::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + centerX = iff.read_float (); + centerZ = iff.read_float (); + radius = iff.read_float (); + radiusSquared = sqr (radius); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + float unused = iff.read_float (); + UNREF (unused); + + centerX = iff.read_float (); + centerZ = iff.read_float (); + radius = iff.read_float (); + radiusSquared = sqr (radius); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + centerX = iff.read_float (); + centerZ = iff.read_float (); + radius = iff.read_float (); + radiusSquared = sqr (radius); + + setFeatherFunction (static_cast (iff.read_int32 ())); + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void BoundaryCircle::save (Iff& iff) const +{ + iff.insertForm (TAG_0002); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (centerX); + iff.insertChunkData (centerZ); + iff.insertChunkData (radius); + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- +// +// BoundaryRectangle +// +BoundaryRectangle::BoundaryRectangle () : + TerrainGenerator::Boundary (TAG_BREC, TGBT_rectangle), + rectangle (), + innerRectangle (), + m_useTransform (false), + m_transform (), + m_localWaterTable (false), + m_localGlobalWaterTable (false), + m_localWaterTableHeight (0), + m_localWaterTableShaderSize (2.f), + m_localWaterTableShaderTemplateName (0), + m_waterType(TGWT_water) +{ +} + +//------------------------------------------------------------------- + +BoundaryRectangle::~BoundaryRectangle () +{ + if (m_localWaterTableShaderTemplateName) + { + delete [] m_localWaterTableShaderTemplateName; + m_localWaterTableShaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +const Vector2d BoundaryRectangle::getCenter () const +{ + return rectangle.getCenter (); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setRectangle (const Rectangle2d& newRectangle) +{ + rectangle = newRectangle; + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setFeatherDistance (const float newFeatherDistance) +{ + Boundary::setFeatherDistance (newFeatherDistance); + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setWaterType (TerrainGeneratorWaterType newWaterType) +{ + m_waterType = newWaterType; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::recalculate () +{ + //-- fixup coordinates + if (rectangle.x0 > rectangle.x1) + std::swap (rectangle.x0, rectangle.x1); + + if (rectangle.y0 > rectangle.y1) + std::swap (rectangle.y0, rectangle.y1); + + //-- find out which is smaller + const float width = rectangle.getWidth (); + const float height = rectangle.getHeight (); + const float feather = 0.5f * std::min (width, height) * getFeatherDistance (); + + //-- compute inner rectangle + innerRectangle = rectangle; + innerRectangle.x0 += feather; + innerRectangle.y0 += feather; + innerRectangle.x1 -= feather; + innerRectangle.y1 -= feather; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::translate (const Vector2d& translation) +{ + rectangle.translate (translation.x, translation.y); + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::scale (const float scalar) +{ + rectangle.scale (scalar); + + recalculate (); +} + +//------------------------------------------------------------------- + +float BoundaryRectangle::isWithin (float worldX, float worldZ) const +{ + if (m_useTransform) + { + const Vector2d transformed = m_transform.rotateTranslate_p2l (Vector2d (worldX, worldZ)); + + worldX = transformed.x; + worldZ = transformed.y; + } + + //-- test outside + if (!rectangle.isWithin (worldX, worldZ)) + return 0.f; + + //-- do we need to feather? + if (getFeatherDistance () == 0.f) + return 1.f; + + //-- test inside + if (innerRectangle.isWithin (worldX, worldZ)) + return 1.f; + + const float left = worldX - rectangle.x0; + const float right = rectangle.x1 - worldX; + const float top = worldZ - rectangle.y0; + const float bottom = rectangle.y1 - worldZ; + + //-- find closest edge + const float width = rectangle.getWidth (); + const float height = rectangle.getHeight (); + const float feather = 0.5f * std::min (width, height) * getFeatherDistance (); + + float distance = feather; + + if (left < distance) + distance = left; + + if (right < distance) + distance = right; + + if (top < distance) + distance = top; + + if (bottom < distance) + distance = bottom; + + return distance / feather; +} + +//------------------------------------------------------------------- + +bool BoundaryRectangle::intersects(const Rectangle2d& other) const +{ + if (m_useTransform) + { + Rectangle2d localRect; + m_transform.rotateTranslate_p2l(localRect, other); + return localRect.intersects(rectangle); + } + else + { + return other.intersects(rectangle); + } +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const +{ + if (m_useTransform) + { + this->BaseClass::scanConvertGT(o_data, scanArea, numberOfPoles); + return; + } + + if (!rectangle.intersects(scanArea)) + { + return; + } + + const float real2Sample = float(numberOfPoles-1) / (scanArea.y1 - scanArea.y0); + + const Rectangle2d rect( + (rectangle.x0 - scanArea.x0)*real2Sample, + (rectangle.y0 - scanArea.y0)*real2Sample, + (rectangle.x1 - scanArea.x0)*real2Sample, + (rectangle.y1 - scanArea.y0)*real2Sample + ); + + const int zmin = std::max(0, int(ceil(rect.y0))); + const int zmax = std::min(numberOfPoles-1, int(floor(rect.y1))); + if (zmax=zmin) + { + if (zchange>zmax) + { + zchange=zmax; + } + for (;z<=zchange;z++) + { + const float zfeather = float(z) - rect.y0; + float *destRow = o_data + z*numberOfPoles; + for (x=xmin;x<=xmax;x++) + { + const float xfeather0 = float(x) - rect.x0; + const float xfeather1 = rect.x1 - float(x); + const float xfeather = std::min(xfeather0, xfeather1); + const float feather = std::min(xfeather, zfeather); + + float amount = feather / maxFeather; + amount = Feather(getFeatherFunction()).feather(0.f, 1.f, amount); + if (amount>destRow[x]) + { + destRow[x]=amount; + } + } + } + } + + zchange=int(floor(rect.y1-maxFeather)); + if (zchange>zmax) + { + zchange=zmax; + } + for (;z<=zchange;z++) + { + float *destRow = o_data + z*numberOfPoles; + + for (x=xmin;x<=xmax;x++) + { + const float xfeather0 = float(x) - rect.x0; + const float xfeather1 = rect.x1 - float(x); + const float xfeather = std::min(xfeather0, xfeather1); + float amount = xfeather / maxFeather; + if (amount>1.0f) + { + destRow[x]=1.0f; + } + else + { + amount = Feather(getFeatherFunction()).feather(0.f, 1.f, amount); + if (amount>destRow[x]) + { + destRow[x]=amount; + } + } + } + } + + for (;z<=zmax;z++) + { + const float zfeather = rect.y1 - float(z); + float *destRow = o_data + z*numberOfPoles; + for (x=xmin;x<=xmax;x++) + { + const float xfeather0 = float(x) - rect.x0; + const float xfeather1 = rect.x1 - float(x); + const float xfeather = std::min(xfeather0, xfeather1); + const float feather = std::min(xfeather, zfeather); + + float amount = feather / maxFeather; + amount = Feather(getFeatherFunction()).feather(0.f, 1.f, amount); + if (amount>destRow[x]) + { + destRow[x]=amount; + } + } + } + } +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::expand (Rectangle2d& extent) const +{ + if (m_useTransform) + { + const Vector2d center = rectangle.getCenter (); + const Vector2d p0 = Vector2d (rectangle.x0, rectangle.y0) - center; + const Vector2d p1 = Vector2d (rectangle.x1, rectangle.y1) - center; + const float magnitude = std::max (p0.magnitude (), p1.magnitude ()); + const Vector2d position = m_transform.getPosition_p (); + + extent.expand (position.x - magnitude, position.y - magnitude); + extent.expand (position.x + magnitude, position.y + magnitude); + } + else + { + extent.expand (rectangle.x0, rectangle.y0); + extent.expand (rectangle.x1, rectangle.y1); + } +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setCenter (const Vector2d& center) +{ + m_useTransform = true; + m_transform.setPosition_p (center); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setRotation (const float angle) +{ + m_useTransform = true; + m_transform.resetRotate_l2p (); + m_transform.yaw_l (angle); +} + +//------------------------------------------------------------------- + +bool BoundaryRectangle::isLocalWaterTable () const +{ + return m_localWaterTable; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setLocalWaterTable (bool const localWaterTable) +{ + m_localWaterTable = localWaterTable; +} + +//------------------------------------------------------------------- + +bool BoundaryRectangle::isLocalGlobalWaterTable () const +{ + return m_localGlobalWaterTable; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setLocalGlobalWaterTable (bool const localGlobalWaterTable) +{ + m_localGlobalWaterTable = localGlobalWaterTable; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setLocalWaterTableHeight (float const localWaterTableHeight) +{ + m_localWaterTableHeight = localWaterTableHeight; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setLocalWaterTableShaderSize (float const localWaterTableShaderSize) +{ + m_localWaterTableShaderSize = localWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::setLocalWaterTableShaderTemplateName (char const * const localWaterTableShaderTemplateName) +{ + if (m_localWaterTableShaderTemplateName) + { + delete [] m_localWaterTableShaderTemplateName; + m_localWaterTableShaderTemplateName = 0; + } + + if (localWaterTableShaderTemplateName) + m_localWaterTableShaderTemplateName = DuplicateString (localWaterTableShaderTemplateName); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + rectangle.x0 = iff.read_float (); + rectangle.y0 = iff.read_float (); + rectangle.x1 = iff.read_float (); + rectangle.y1 = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + float unused = iff.read_float (); + UNREF (unused); + + rectangle.x0 = iff.read_float (); + rectangle.y0 = iff.read_float (); + rectangle.x1 = iff.read_float (); + rectangle.y1 = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + rectangle.x0 = iff.read_float (); + rectangle.y0 = iff.read_float (); + rectangle.x1 = iff.read_float (); + rectangle.y1 = iff.read_float (); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + rectangle.x0 = iff.read_float (); + rectangle.y0 = iff.read_float (); + rectangle.x1 = iff.read_float (); + rectangle.y1 = iff.read_float (); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + m_localWaterTable = iff.read_int32 () != 0; + m_localGlobalWaterTable = iff.read_int32 () != 0; + m_localWaterTableHeight = iff.read_float (); + m_localWaterTableShaderSize = iff.read_float (); + m_localWaterTableShaderTemplateName = iff.read_string (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + rectangle.x0 = iff.read_float (); + rectangle.y0 = iff.read_float (); + rectangle.x1 = iff.read_float (); + rectangle.y1 = iff.read_float (); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + m_localWaterTable = iff.read_int32 () != 0; + m_localGlobalWaterTable = iff.read_int32 () != 0; + m_localWaterTableHeight = iff.read_float (); + m_localWaterTableShaderSize = iff.read_float (); + m_localWaterTableShaderTemplateName = iff.read_string (); + setWaterType(static_cast (iff.read_int32 ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void BoundaryRectangle::save (Iff& iff) const +{ + iff.insertForm (TAG_0004); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (rectangle.x0); + iff.insertChunkData (rectangle.y0); + iff.insertChunkData (rectangle.x1); + iff.insertChunkData (rectangle.y1); + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + + iff.insertChunkData (m_localWaterTable ? static_cast (1) : static_cast (0)); + iff.insertChunkData (m_localGlobalWaterTable ? static_cast (1) : static_cast (0)); + iff.insertChunkData (m_localWaterTableHeight); + iff.insertChunkData (m_localWaterTableShaderSize); + iff.insertChunkString (m_localWaterTableShaderTemplateName ? m_localWaterTableShaderTemplateName : ""); + iff.insertChunkData (static_cast (getWaterType())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- +// +// BoundaryPoly +// +BoundaryPoly::BoundaryPoly (Tag newTag, TerrainGeneratorBoundaryType newType) : + TerrainGenerator::Boundary (newTag, newType), + pointList (), + extent () +{ +} + +//------------------------------------------------------------------- + +BoundaryPoly::~BoundaryPoly () +{ +} + +//------------------------------------------------------------------- + +const Vector2d BoundaryPoly::getCenter () const +{ + return extent.getCenter (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::addPoint (const Vector2d& point) +{ + pointList.add (point); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::replacePoint (const int index, const Vector2d& newPoint) +{ + pointList [index] = newPoint; + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::removePoint (const int index) +{ + pointList.removeIndexAndCompactList (index); + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::clearPointList () +{ + pointList.clear (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::copyPointList (const ArrayList& newPointList) +{ + pointList = newPointList; + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::recalculate () +{ + extent.x0 = FLT_MAX; + extent.y0 = FLT_MAX; + extent.x1 = -FLT_MAX; + extent.y1 = -FLT_MAX; + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + extent.expand (pointList [i].x, pointList [i].y); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::rotate (const float angle) +{ + if (pointList.getNumberOfElements () == 0) + return; + + Vector2d center; + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + center += pointList [i]; + + center.x /= static_cast (pointList.getNumberOfElements ()); + center.y /= static_cast (pointList.getNumberOfElements ()); + + rotate (angle, center); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::rotate (const float angle, const Vector2d& center) +{ + if (pointList.getNumberOfElements () == 0) + return; + + const float cosAngle = cos (angle); + const float sinAngle = sin (angle); + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + { + Vector2d point; + point.x = pointList [i].x - center.x; + point.y = pointList [i].y - center.y; + + Vector2d newPoint; + newPoint.x = center.x + point.x * cosAngle - point.y * sinAngle; + newPoint.y = center.y + point.x * sinAngle + point.y * cosAngle; + + pointList [i] = newPoint; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::translate (const Vector2d& translation) +{ + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + pointList [i] += translation; + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::scale (const float scalar) +{ + if (pointList.getNumberOfElements () == 0) + return; + + Vector2d center; + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + center += pointList [i]; + + center.x /= static_cast (pointList.getNumberOfElements ()); + center.y /= static_cast (pointList.getNumberOfElements ()); + + for (i = 0; i < pointList.getNumberOfElements (); i++) + { + pointList [i].x = (pointList [i].x - center.x) * scalar + center.x; + pointList [i].y = (pointList [i].y - center.y) * scalar + center.y; + } + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPoly::expand (Rectangle2d& parentExtent) const +{ + parentExtent.expand (extent.x0, extent.y0); + parentExtent.expand (extent.x1, extent.y1); +} + +//------------------------------------------------------------------- + +bool BoundaryPoly::intersects(const Rectangle2d& other) const +{ + return other.intersects(extent); +} + +//------------------------------------------------------------------- +// +// BoundaryPolygon +// +BoundaryPolygon::BoundaryPolygon () : + BoundaryPoly (TAG_BPOL, TGBT_polygon), + localWaterTable (false), + localWaterTableHeight (0), + localWaterTableShaderSize (2.f), + localWaterTableShaderTemplateName (0), + m_waterType(TGWT_water) +{ +} + +//------------------------------------------------------------------- + +BoundaryPolygon::~BoundaryPolygon () +{ + if (localWaterTableShaderTemplateName) + { + delete [] localWaterTableShaderTemplateName; + localWaterTableShaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +bool BoundaryPolygon::isLocalWaterTable () const +{ + return localWaterTable; +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::setLocalWaterTable (const bool newLocalWaterTable) +{ + localWaterTable = newLocalWaterTable; +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::setLocalWaterTableHeight (const float newLocalWaterTableHeight) +{ + localWaterTableHeight = newLocalWaterTableHeight; +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::setLocalWaterTableShaderSize (const float newLocalWaterTableShaderSize) +{ + localWaterTableShaderSize = newLocalWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::setLocalWaterTableShaderTemplateName (const char* newLocalWaterTableShaderTemplateName) +{ + if (localWaterTableShaderTemplateName) + { + delete [] localWaterTableShaderTemplateName; + localWaterTableShaderTemplateName = 0; + } + + if (newLocalWaterTableShaderTemplateName) + localWaterTableShaderTemplateName = DuplicateString (newLocalWaterTableShaderTemplateName); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::setWaterType (TerrainGeneratorWaterType newWaterType) +{ + m_waterType = newWaterType; +} + +//------------------------------------------------------------------- + +float BoundaryPolygon::isWithin (const float worldX, const float worldZ) const +{ + if (!extent.isWithin (worldX, worldZ)) + return 0.f; + + bool in = false; + + const int n = pointList.getNumberOfElements (); + + //-- check to make sure the point is inside the shape + int i; + int j; + for (i = 0, j = n - 1; i < n; j = i++) + if ((((pointList [i].y <= worldZ) && (worldZ < pointList [j].y)) || ((pointList [j].y <= worldZ) && (worldZ < pointList [i].y))) && (worldX < (pointList [j].x - pointList [i].x) * (worldZ - pointList [i].y) / (pointList [j].y - pointList [i].y) + pointList [i].x)) + in = !in; + + if (!in) + return 0.f; + + if (getFeatherDistance () == 0.f) + return 1.f; + + const float featherDistanceSquared = sqr (getFeatherDistance ()); + + float distanceSquared = featherDistanceSquared; + + for (i = 0; i < n; ++i) + { + const float x = pointList [i].x; + const float y = pointList [i].y; + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + + for (i = 0, j = n - 1; i < n; j = i++) + { + //-- compute u on parametric line + const float x1 = pointList [j].x; + const float y1 = pointList [j].y; //lint !e578 //-- hides y1 (double) + const float x2 = pointList [i].x; + const float y2 = pointList [i].y; + + const float u = ((worldX - x1) * (x2 - x1) + (worldZ - y1) * (y2 - y1)) / (sqr (x1 - x2) + sqr (y1 - y2)); + if (u >= 0 && u <= 1) + { + const float x = x1 + u * (x2 - x1); + const float y = y1 + u * (y2 - y1); + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + } + + if (!WithinEpsilonInclusive (featherDistanceSquared, distanceSquared, 0.0001f)) + return sqrt (distanceSquared) / getFeatherDistance (); + + return 1.f; +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + case TAG_0006: + load_0006 (iff); + break; + + case TAG_0007: + load_0007 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } + + //-- make sure we update our bounding box + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + Vector2d point; + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + float unused = iff.read_float (); + UNREF (unused); + + Vector2d point; + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + localWaterTable = iff.read_int32 () != 0; + localWaterTableHeight = iff.read_float (); + localWaterTableShaderTemplateName = iff.read_string (); + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + localWaterTable = iff.read_int32 () != 0; + localWaterTableHeight = iff.read_float (); + localWaterTableShaderSize = iff.read_float (); + localWaterTableShaderTemplateName = iff.read_string (); + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + localWaterTable = iff.read_int32 () != 0; + localWaterTableHeight = iff.read_float (); + localWaterTableShaderSize = iff.read_float (); + localWaterTableShaderTemplateName = iff.read_string (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0006 (Iff& iff) +{ + iff.enterForm (TAG_0006); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + localWaterTable = iff.read_int32 () != 0; + localWaterTableHeight = iff.read_float (); + localWaterTableShaderSize = iff.read_float (); + IGNORE_RETURN (iff.read_int32 ()); + localWaterTableShaderTemplateName = iff.read_string (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0006); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::load_0007 (Iff& iff) +{ + iff.enterForm (TAG_0007); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + + localWaterTable = iff.read_int32 () != 0; + localWaterTableHeight = iff.read_float (); + localWaterTableShaderSize = iff.read_float (); + setWaterType(static_cast (iff.read_int32 ())); + //IGNORE_RETURN (iff.read_int32 ()); + localWaterTableShaderTemplateName = iff.read_string (); + + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0007); +} + +//------------------------------------------------------------------- + +void BoundaryPolygon::save (Iff& iff) const +{ + iff.insertForm (TAG_0007); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (pointList.getNumberOfElements ()); + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + { + iff.insertChunkData (pointList [i].x); + iff.insertChunkData (pointList [i].y); + } + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (localWaterTable ? static_cast (1) : static_cast (0)); + iff.insertChunkData (localWaterTableHeight); + iff.insertChunkData (localWaterTableShaderSize); + iff.insertChunkData (static_cast (getWaterType())); + iff.insertChunkString (localWaterTableShaderTemplateName ? localWaterTableShaderTemplateName : ""); + + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0007); +} + +//------------------------------------------------------------------- +// +// BoundaryPolyline +// +BoundaryPolyline::BoundaryPolyline () : + BoundaryPoly (TAG_BPLN, TGBT_polyline), + m_width (2.f) +{ +} + +//------------------------------------------------------------------- + +BoundaryPolyline::~BoundaryPolyline () +{ +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::setWidth (const float newWidth) +{ + m_width = newWidth; + + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::recalculate () +{ + BoundaryPoly::recalculate (); + + extent.x0 -= m_width; + extent.x1 += m_width; + extent.y0 -= m_width; + extent.y1 += m_width; +} + +//------------------------------------------------------------------- + +float BoundaryPolyline::isWithin (const float worldX, const float worldZ) const +{ + if (!extent.isWithin (worldX, worldZ)) + return 0.f; + + const float widthSquared = sqr (m_width); + + float distanceSquared = widthSquared; + + //-- first, scan how far we are from the points + { + const int n = pointList.getNumberOfElements (); + int i; + for (i = 0; i < n; ++i) + { + const float x = pointList [i].x; + const float y = pointList [i].y; + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + } + + //-- next, scan each line + { + const int n = pointList.getNumberOfElements () - 1; + int i; + for (i = 0; i < n; ++i) + { + const float x1 = pointList [i].x; + const float y1 = pointList [i].y; //lint !e578 //-- hides y1 (double) + const float x2 = pointList [i + 1].x; + const float y2 = pointList [i + 1].y; + + const float u = ((worldX - x1) * (x2 - x1) + (worldZ - y1) * (y2 - y1)) / (sqr (x2 - x1) + sqr (y2 - y1)); + if (u >= 0 && u <= 1) + { + const float x = x1 + u * (x2 - x1); + const float y = y1 + u * (y2 - y1); + const float thisDistanceSquared = sqr (worldX - x) + sqr (worldZ - y); + if (thisDistanceSquared < distanceSquared) + distanceSquared = thisDistanceSquared; + } + } + } + + if (distanceSquared < widthSquared) + { + const float newFeatherDistance = m_width * (1.f - getFeatherDistance ()); + const float newFeatherDistanceSquared = sqr (newFeatherDistance); + + if (distanceSquared < newFeatherDistanceSquared) + return 1.f; + + return 1.f - (sqrt (distanceSquared) - newFeatherDistance) / (m_width - newFeatherDistance); + } + + return 0.f; +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } + + //-- make sure we update our bounding box + recalculate (); +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + setWidth (iff.read_float ()); + + int n = iff.getChunkLengthLeft (sizeof (Vector2d)); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + setWidth (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + n = iff.read_int32 (); // old height list + for(i = 0; i < n; i++) + { + IGNORE_RETURN(iff.read_float()); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + setWidth (iff.read_float ()); + IGNORE_RETURN(iff.read_int32()); // old has widths + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void BoundaryPolyline::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + Vector2d point; + point.x = iff.read_float (); + point.y = iff.read_float (); + + pointList.add (point); + } + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (iff.read_float ()); + setWidth (iff.read_float ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + + + +void BoundaryPolyline::save (Iff& iff) const +{ + iff.insertForm (TAG_0003); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (pointList.getNumberOfElements ()); + + int i; + for (i = 0; i < pointList.getNumberOfElements (); i++) + { + iff.insertChunkData (pointList [i].x); + iff.insertChunkData (pointList [i].y); + } + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (m_width); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.h b/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.h new file mode 100644 index 00000000..e718d7b6 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Boundary.h @@ -0,0 +1,378 @@ +//=================================================================== +// +// Boundary.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_Boundary_H +#define INCLUDED_Boundary_H + +//=================================================================== + +#include "sharedMath/Rectangle2d.h" +#include "sharedMath/Transform2d.h" +#include "sharedMath/Vector2d.h" +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class BoundaryCircle : public TerrainGenerator::Boundary +{ +private: + + float centerX; + float centerZ; + float radius; + float radiusSquared; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + +private: + + BoundaryCircle (const BoundaryCircle& rhs); + BoundaryCircle& operator= (const BoundaryCircle& rhs); + +public: + + BoundaryCircle (); + virtual ~BoundaryCircle (); + + float getCenterX () const; + float getCenterZ () const; + float getRadius () const; + void setCircle (float newCenterX, float newCenterZ, float newRadius); + + virtual void translate (const Vector2d& translation); + virtual void scale (float scalar); + virtual float isWithin (float worldX, float worldZ) const; + virtual bool intersects(const Rectangle2d& other) const; + virtual void scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual void expand (Rectangle2d& extent) const; + virtual const Vector2d getCenter () const; + virtual void setCenter (const Vector2d& center); +}; + +//------------------------------------------------------------------- + +inline float BoundaryCircle::getCenterX () const +{ + return centerX; +} + +//------------------------------------------------------------------- + +inline float BoundaryCircle::getCenterZ () const +{ + return centerZ; +} + +//------------------------------------------------------------------- + +inline float BoundaryCircle::getRadius () const +{ + return radius; +} + +//=================================================================== + +class BoundaryRectangle : public TerrainGenerator::Boundary +{ +private: + + typedef TerrainGenerator::Boundary BaseClass; + + Rectangle2d rectangle; + Rectangle2d innerRectangle; + + bool m_useTransform; + Transform2d m_transform; + + bool m_localWaterTable; + bool m_localGlobalWaterTable; + float m_localWaterTableHeight; + float m_localWaterTableShaderSize; + char * m_localWaterTableShaderTemplateName; + TerrainGeneratorWaterType m_waterType; + +private: + + void recalculate (); + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + +private: + + BoundaryRectangle (const BoundaryRectangle& rhs); + BoundaryRectangle& operator= (const BoundaryRectangle& rhs); + +public: + + BoundaryRectangle (); + virtual ~BoundaryRectangle (); + + void setRectangle (const Rectangle2d& newRectangle); + const Rectangle2d& getRectangle () const; + + virtual void setFeatherDistance (float newFeatherDistance); + virtual void translate (const Vector2d& translation); + virtual void scale (float scalar); + virtual float isWithin (float worldX, float worldZ) const; + virtual bool intersects(const Rectangle2d& other) const; + virtual void scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual void expand (Rectangle2d& extent) const; + virtual const Vector2d getCenter () const; + virtual void setCenter (const Vector2d& center); + virtual void setRotation (float angle); + + bool isLocalWaterTable () const; + void setLocalWaterTable (bool localWaterTable); + bool isLocalGlobalWaterTable () const; + void setLocalGlobalWaterTable (bool localGlobalWaterTable); + float getLocalWaterTableHeight () const; + void setLocalWaterTableHeight (float localWaterTableHeight); + float getLocalWaterTableShaderSize () const; + void setLocalWaterTableShaderSize (float localWaterTableShaderSize); + char const * getLocalWaterTableShaderTemplateName () const; + void setLocalWaterTableShaderTemplateName (char const * localWaterTableShaderTemplateName); + TerrainGeneratorWaterType getWaterType () const; + void setWaterType (TerrainGeneratorWaterType newWaterType); + +}; + +//------------------------------------------------------------------- + +inline const Rectangle2d& BoundaryRectangle::getRectangle () const +{ + return rectangle; +} + +//------------------------------------------------------------------- + +inline float BoundaryRectangle::getLocalWaterTableHeight () const +{ + return m_localWaterTableHeight; +} + +//------------------------------------------------------------------- + +inline float BoundaryRectangle::getLocalWaterTableShaderSize () const +{ + return m_localWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +inline const char* BoundaryRectangle::getLocalWaterTableShaderTemplateName () const +{ + return m_localWaterTableShaderTemplateName; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorWaterType BoundaryRectangle::getWaterType () const +{ + return m_waterType; +} + +//=================================================================== + +class BoundaryPoly : public TerrainGenerator::Boundary +{ +protected: + + ArrayList pointList; + Rectangle2d extent; + +protected: + + virtual void recalculate (); + +private: + + BoundaryPoly (const BoundaryPoly& rhs); + BoundaryPoly& operator= (const BoundaryPoly& rhs); + +public: + + BoundaryPoly (Tag newTag, TerrainGeneratorBoundaryType newType); + virtual ~BoundaryPoly ()=0; + + virtual void rotate (float angle); + virtual void rotate (float angle, const Vector2d& center); + virtual void translate (const Vector2d& translation); + virtual void scale (float scalar); + virtual void expand (Rectangle2d& extent) const; + virtual const Vector2d getCenter () const; + + virtual bool intersects(const Rectangle2d& other) const; + + const ArrayList& getPointList () const; + int getNumberOfPoints () const; + const Vector2d& getPoint (int index) const; + void addPoint (const Vector2d& point); + void replacePoint (int index, const Vector2d& point); + void removePoint (int index); + void clearPointList (); + void copyPointList (const ArrayList& newPointList); +}; + +//------------------------------------------------------------------- + +inline const ArrayList& BoundaryPoly::getPointList () const +{ + return pointList; +} + +//------------------------------------------------------------------- + +inline int BoundaryPoly::getNumberOfPoints () const +{ + return pointList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const Vector2d& BoundaryPoly::getPoint (int index) const +{ + return pointList [index]; +} + +//=================================================================== + +class BoundaryPolygon : public BoundaryPoly +{ +private: + + bool localWaterTable; + float localWaterTableHeight; + float localWaterTableShaderSize; + char* localWaterTableShaderTemplateName; + TerrainGeneratorWaterType m_waterType; + + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + void load_0006 (Iff& iff); + void load_0007 (Iff& iff); + +private: + + BoundaryPolygon (const BoundaryPolygon& rhs); + BoundaryPolygon& operator= (const BoundaryPolygon& rhs); + +public: + + BoundaryPolygon (); + virtual ~BoundaryPolygon (); + + virtual float isWithin (float worldX, float worldZ) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + + bool isLocalWaterTable () const; + void setLocalWaterTable (bool newLocalWaterTable); + float getLocalWaterTableHeight () const; + void setLocalWaterTableHeight (float newLocalWaterTableHeight); + float getLocalWaterTableShaderSize () const; + void setLocalWaterTableShaderSize (float newLocalWaterTableShaderSize); + const char* getLocalWaterTableShaderTemplateName () const; + void setLocalWaterTableShaderTemplateName (const char* newLocalWaterTableShaderTemplateName); + TerrainGeneratorWaterType getWaterType () const; + void setWaterType (TerrainGeneratorWaterType newWaterType); + +}; + +//------------------------------------------------------------------- + +inline float BoundaryPolygon::getLocalWaterTableHeight () const +{ + return localWaterTableHeight; +} + +//------------------------------------------------------------------- + +inline float BoundaryPolygon::getLocalWaterTableShaderSize () const +{ + return localWaterTableShaderSize; +} + +//------------------------------------------------------------------- + +inline const char* BoundaryPolygon::getLocalWaterTableShaderTemplateName () const +{ + return localWaterTableShaderTemplateName; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorWaterType BoundaryPolygon::getWaterType () const +{ + return m_waterType; +} + +//=================================================================== + +class BoundaryPolyline : public BoundaryPoly +{ +private: + + float m_width; + +private: + + virtual void recalculate (); + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + +private: + + BoundaryPolyline (const BoundaryPolyline& rhs); + BoundaryPolyline& operator= (const BoundaryPolyline& rhs); + +public: + + BoundaryPolyline (); + virtual ~BoundaryPolyline (); + + virtual float isWithin (float worldX, float worldZ) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + + void setWidth (float newWidth); + float getWidth () const; +}; + +//------------------------------------------------------------------- + +inline float BoundaryPolyline::getWidth () const +{ + return m_width; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.cpp new file mode 100644 index 00000000..02ad5c0c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.cpp @@ -0,0 +1,126 @@ +//=================================================================== +// +// ColorRamp256.cpp +// asommers +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ColorRamp256.h" + +#include "sharedFile/Iff.h" + +//=================================================================== + +namespace +{ + const Tag TAG_RAMP = TAG (R,A,M,P); +} + +//=================================================================== + +ColorRamp256::ColorRamp256 () + //lint -esym (1926, ColorRamp256::m_ramp) // not in initializer list + //lint -esym (1926, ColorRamp256::m_node) // not in initializer list +{ + int i; + for (i = 0; i < 256; ++i) + { + m_ramp [i] = PackedRgb::solidBlack; + m_node [i] = false; + } + + m_node [0] = true; + m_node [255] = true; +} + +//------------------------------------------------------------------- + +ColorRamp256::~ColorRamp256 () +{ +} + +//------------------------------------------------------------------- + +void ColorRamp256::setColor (int index, const PackedRgb& color) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + m_ramp [index] = color; +} + +//------------------------------------------------------------------- + +void ColorRamp256::setNode (int index, bool node) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + m_node [index] = node; +} + +//------------------------------------------------------------------- + +void ColorRamp256::setRed (int index, uint8 r) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + m_ramp [index].r = r; +} + +//------------------------------------------------------------------- + +void ColorRamp256::setGreen (int index, uint8 g) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + m_ramp [index].g = g; +} + +//------------------------------------------------------------------- + +void ColorRamp256::setBlue (int index, uint8 b) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + m_ramp [index].b = b; +} + +//------------------------------------------------------------------- + +void ColorRamp256::load (Iff& iff) +{ + iff.enterForm (TAG_RAMP); + iff.enterChunk (TAG_0000); + + int i; + for (i = 0; i < 256; ++i) + { + m_ramp [i].r = iff.read_uint8 (); + m_ramp [i].g = iff.read_uint8 (); + m_ramp [i].b = iff.read_uint8 (); + m_node [i] = iff.read_uint8 () != 0; + } + + iff.exitChunk (); + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ColorRamp256::save (Iff& iff) const +{ + iff.insertForm (TAG_RAMP); + iff.insertChunk (TAG_0000); + + int i; + for (i = 0; i < 256; ++i) + { + iff.insertChunkData (m_ramp [i].r); + iff.insertChunkData (m_ramp [i].g); + iff.insertChunkData (m_ramp [i].b); + iff.insertChunkData (m_node [i] ? static_cast (1) : static_cast (0)); + } + + iff.exitChunk (); + iff.exitForm (); +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.h b/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.h new file mode 100644 index 00000000..72be602e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/ColorRamp256.h @@ -0,0 +1,91 @@ +//=================================================================== +// +// ColorRamp256.h +// asommers +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_ColorRamp_H +#define INCLUDED_ColorRamp_H + +//=================================================================== + +#include "sharedMath/PackedRgb.h" + +class Iff; + +//=================================================================== + +class ColorRamp256 +{ +public: + + ColorRamp256 (); + ~ColorRamp256 (); + + void setColor (int index, const PackedRgb& color); + void setRed (int index, uint8 r); + void setGreen (int index, uint8 g); + void setBlue (int index, uint8 b); + void setNode (int index, bool node); + + const PackedRgb& getColor (int index) const; + uint8 getRed (int index) const; + uint8 getGreen (int index) const; + uint8 getBlue (int index) const; + bool getNode (int index) const; + + void load (Iff& iff); + void save (Iff& iff) const; + +private: + + PackedRgb m_ramp [256]; + bool m_node [256]; +}; + +//------------------------------------------------------------------- + +inline const PackedRgb& ColorRamp256::getColor (int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + return m_ramp [index]; +} + +//------------------------------------------------------------------- + +inline bool ColorRamp256::getNode (int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + return m_node [index]; +} + +//------------------------------------------------------------------- + +inline uint8 ColorRamp256::getRed (int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + return m_ramp [index].r; +} + +//------------------------------------------------------------------- + +inline uint8 ColorRamp256::getGreen (int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + return m_ramp [index].g; +} + +//------------------------------------------------------------------- + +inline uint8 ColorRamp256::getBlue (int index) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, index, 256); + return m_ramp [index].b; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.cpp new file mode 100644 index 00000000..efd2f614 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.cpp @@ -0,0 +1,233 @@ +//=================================================================== +// +// CoordinateHash.cpp +// bearhart 6-30-2005 +// +// copyright 2005, Sony Online Entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/CoordinateHash.h" +#include "sharedRandom/FastRandomGenerator.h" + +//=================================================================== + +namespace +{ + /* + unsigned int shuffler1[256] = { + 0xd987a3ee,0xcc2ab970,0xde1371a6,0xf8fa5333,0x43be3997,0x7b9d4893,0x8bbc3f47,0x1bab3ec6, + 0x4e6fd45b,0xb35efe80,0x7e9549eb,0x416276de,0x016eded4,0x31a16f30,0x5be25d3a,0x149f0a1e, + 0x0c4f2646,0xe726ccb6,0x7da990d6,0x974250f6,0x2958e3bc,0xf3b220c7,0x320228cf,0xfc37e8bf, + 0x0dc2db52,0x375bbd88,0xbea058e1,0xc7784c45,0xa80f930c,0xb9bb45a7,0x3deff0af,0x723bdced, + 0x5c80c2f8,0xf04769b4,0x774ebc0a,0x189a1e29,0x7c668dd0,0x0e84fc98,0xa9350bc2,0xd2e89c65, + 0xbf3c5156,0xadcc464d,0x19eea891,0x1185793b,0x38d1b60d,0x274ca734,0x92e5c1d1,0x1dd9b1fb, + 0xc2d44fa5,0x8f760df2,0x95ae6eb8,0xd494050b,0x479edd2a,0x6138dae4,0x4228e1e0,0x2c7acf41, + 0x4b0e7a0f,0x732b425c,0xab11c696,0x6ae6ce7f,0xc3fe2254,0x5ff36c7a,0x8d747443,0xf432f2a1, + 0x808aeddd,0x0491a53d,0xb01b568e,0x66c5e758,0x487d3357,0x53e46b07,0x8a6c43da,0xa20a090e, + 0x5ef0ebc0,0x75b994cc,0x7fdf13f4,0xdf6df3a8,0x6420c0ff,0xcecb1812,0xaad3812f,0x54b1198f, + 0xc471e017,0x3cecb553,0x2677c535,0xb460b089,0x511c3690,0x506a78c1,0x1a721a06,0x78962392, + 0x585fa68b,0x2e599f1a,0x94edca49,0x9b5435b7,0x17ff38e7,0xe6b0c4dc,0x10f20777,0xaecdd387, + 0xd80c113c,0x09db2d3e,0xe5f1ee5e,0x9d680471,0x2050c86f,0x9adad6b5,0x7a3954ec,0xbdd8a061, + 0x575d21ca,0xe30d60b2,0x13c7917e,0x3bb35a66,0xdd0730fd,0x63fb83bd,0xd5ba12cd,0x2b0befac, + 0x0b319e69,0xe024662e,0x6fe91086,0x88922c36,0x798c0f24,0x68567531,0x4d9963d5,0xba2d721c, + 0xfd491cbe,0x242c7c75,0xcf63159d,0xf1d27b08,0xc01ec3f0,0x3f08f18d,0x307b3210,0x1c14d727, + 0xb6d6a994,0xd79cb7d9,0xb18e8a99,0x98f77d83,0xe9e18079,0x2a06ae48,0x55f53450,0xa5e768ba, + 0x56ce779a,0x454661fa,0x764bf659,0xcb5c7fa0,0xf56967ce,0x22b785e9,0xe273086b,0xd6d0f5a9, + 0x23452e5d,0xed18a4fe,0x4f64bf00,0x46e39895,0xbc17a2ef,0x82d5996a,0xdcc1d864,0xe812e238, + 0x059088d7,0x8cb4d501,0x81ac3a05,0xac7fd2d8,0x89c9aadb,0x8e10417d,0x9f7c3b6c,0x49b6954f, + 0x87ddcb1d,0x966b31f9,0x0f44cd73,0xdbbf2a44,0x0a330ce6,0x3e70b8a4,0xb28b17f3,0xef61a151, + 0xd122c782,0xf9013cea,0x909b40b9,0xc9518481,0xb8f9ab42,0xeb3a2914,0x448fe9e3,0x744a926e, + 0x361a8fd2,0xc5dce6e8,0xc8c05b16,0x1e051fb3,0x2882be1b,0x60345f4e,0xd316b27b,0xffa80e6d, + 0xd0fce5f1,0x93008923,0x2d045e19,0x07405755,0x3a57d9d3,0xbb1947a3,0xa7a7fbb1,0x063f2f7c, + 0x86b8259e,0x2167b411,0x9e5327b0,0x5a3d9a5f,0xe4aa6a5a,0x33c44acb,0x034d1b4c,0xf2b57304, + 0x59238609,0x70a46467,0x02a3b325,0xfecfac40,0x65def703,0xcd979be2,0x8509ec26,0x6efd1d28, + 0xe19324f5,0xa3552b13,0x99eabb68,0xa03087a2,0xca5aeaad,0xf6ebff3f,0x164102c9,0xeaf41620, + 0xc12e37bb,0x69adfde5,0x83484e78,0x35211422,0x6c7eaf1f,0xb7655c2c,0xaf0352ab,0x3486ba4b, + 0x52794d9b,0x00af658c,0x1227f9ae,0x4a434439,0x671f709c,0x9ca68b37,0x91520674,0xfb81f49f, + 0x40ca8c02,0xda1d9d2b,0x08a2d0aa,0xc6bd9763,0x39e0d132,0xf7887e62,0x6275fafc,0x5dc63dc5, + 0x71f8dfc8,0xa6c80018,0x6dd755df,0xec8d9676,0xee298ec4,0x4c158272,0x2f3e4bf7,0xa42f6285, + 0xfa36ad60,0x1f98c915,0xa1f6038a,0x25c36d4a,0x1583f8c3,0xb589e421,0x84a50184,0x6b25592d + }; + + unsigned int shuffler2[256] = { + 0x2f2300f3,0xb970f3aa,0xec01de51,0xd8ff6adf,0xb3a7b1ff,0x7ee5829d,0x4f7dbcbe,0x3787f8d7, + 0x28b7a03b,0x36f2eb65,0xaa6669c1,0x962293d9,0xc476842e,0xb2418a6e,0xc8032907,0x80e028fd, + 0x4c9b5572,0x954e19d4,0xf5b58088,0x570ddd6f,0x7804b091,0xcb5a9bde,0x796c39e1,0x38840a2b, + 0x33f1b60a,0x3dd7cd76,0x5851cf8a,0x717550f2,0x2c9f5cca,0xa126105f,0xd9aa1474,0x08c72fc9, + 0x29499e4f,0xf4d08886,0xf0a461f6,0x5b7204cc,0x865edb81,0x7b7cd310,0x4734ad28,0x85809cdc, + 0xce12ac9e,0x18b3b47b,0xe5e932f7,0x6386b7e3,0x5a11a727,0xea1f6500,0xc2443ddb,0x9bb0bb14, + 0x75a1f0e9,0x88cf5a8b,0xd5949d3a,0x17fcc637,0x43d8b938,0xf8e1123e,0x7a3a8b77,0x10c9f92d, + 0xbaac7cda,0x68482755,0x0ebcb3ce,0x1e3b0b7d,0x3eeb09c8,0x916a6416,0x341dc30e,0x8f4631a9, + 0x2a0a078c,0x273ebab3,0xbd2fc005,0xa642b849,0x8ceaffea,0xa91bfbd1,0x1d7e75c3,0x87b8bda0, + 0xb0fe44c6,0x6db926ec,0xeb526f48,0x59165378,0x6e9970b7,0x61b4a647,0xe6dce5c7,0x4e208dd0, + 0x8b6bc8e6,0x5ef735ef,0xa41ad1f8,0xed4b9966,0x6085cb35,0x6768d843,0xa7ed5d5e,0xbb71f75c, + 0x7f59474e,0x3582950b,0x05790508,0xfd7f5e31,0xc098c71d,0xafefe090,0xf6c5ab5b,0x0aaec518, + 0x99f002a4,0xd76e63a2,0xdc402b33,0x56e6bed5,0x0b2b4353,0xcf640db0,0x548321ab,0xe20f7485, + 0x131530fb,0xd4456e19,0x448ac4af,0x3ae3eeb6,0xda812d01,0xf36d73d6,0x66271c11,0x1c5794cb, + 0xf100f567,0x2017f668,0x23ce4996,0xb4bb5606,0x89a66269,0xfeb6bf71,0x425b7fbf,0x4ad43302, + 0xa85666b1,0x7d8b1646,0xbfd9c2b9,0x6f9cc16d,0x726236d8,0xfc89e252,0x16c41d82,0xf93620e2, + 0xdde28589,0x7cbf1fa5,0xa5904bac,0x92af5858,0x1a53aebb,0x9ffbd7cf,0x81ee387e,0x9ef91157, + 0x30917b8e,0x46ad40bd,0x827adaf9,0xe1f4ceba,0xbcbdb261,0xe9f5d07f,0x9cc113fa,0x49614e63, + 0x4b3979c2,0x8a304f70,0x395d4529,0x0d35d404,0x50217ec4,0x6acca921,0xfa633779,0xa210222c, + 0xa0180cae,0x9d73b515,0xca08d50d,0xd10e3f98,0xb6243ca6,0x4d50521e,0x94f85484,0x1192816c, + 0xf7a246ad,0x55d68fb4,0x22f31ac5,0x45ca9809,0xd3775f3d,0x40a03423,0x24334a44,0xde37cce0, + 0xee2c5199,0x5f2991e5,0x2d43f4ee,0x843f7d1a,0x129d0ebc,0xffa50fb8,0x15a3687c,0x981ea464, + 0x009ae962,0x6ce46d80,0x253cafe4,0x74197283,0xac314217,0xe4d2f122,0xe32578f5,0x7654609a, + 0x7009e43f,0x2ec80854,0x9a7b41f1,0x5260ece8,0xcd06fc9c,0x03b1effc,0x0f5cd94b,0xc1b21efe, + 0x26ecea0f,0x0158a345,0x3b28dfed,0x931c2ea3,0x09a959e7,0xfbd5489f,0xb52e3b32,0xad380612, + 0xc513edd2,0x19692a2a,0xbe88fe3c,0xc6c6aaeb,0xef6703dd,0xc38c4d30,0x51db1893,0xd22d7625, + 0x838da5b5,0xe8de2442,0x64df87b2,0xccc3869b,0xdbd3d673,0xe795e6f4,0xf2556724,0x0cdd1713, + 0x69149f95,0xc9cd965a,0xa33dfd1f,0x6bda778f,0x532ad250,0x484a2c5d,0xdff6a2f0,0x779ea81b, + 0xe0d16b6b,0x06a85b8d,0x316fcaa8,0x73979a03,0x2b5ffa4a,0xc7c071d3,0x8d4d3aa1,0x3c323e92, + 0x3f938c36,0x1bfd1b94,0x14ba7a56,0x62ab0134,0x414789cd,0xb84f972f,0xb707e74c,0x6578f2a7, + 0x908ea141,0x07c2927a,0xd065dcc0,0x8e4c8320,0x5c8f4c60,0x21746c6a,0x5d02254d,0x32cbe326, + 0x1f0c8e75,0xae0b2340,0x02fae80c,0xabbee197,0xd6965739,0x97e7901c,0x0405c987,0xb1e81559 + }; + + uint32 _hash1(uint32 x) + { + const uint32 h1 = shuffler[((x>> 0)+ 0)&255]; + const uint32 h2 = shuffler[((x>> 8)+ 64)&255]; + const uint32 h3 = shuffler[((x>>16)+128)&255]; + const uint32 h4 = shuffler[((x>>24)+192)&255]; + + return h1 ^ h2 ^ h3 ^ h4; + } + + uint32 _hash2(uint32 x) + { + const uint32 h1 = shuffler[((x>> 0)+ 64)&255]; + const uint32 h2 = shuffler[((x>> 8)+128)&255]; + const uint32 h3 = shuffler[((x>>16)+192)&255]; + const uint32 h4 = shuffler[((x>>24)+ 0)&255]; + + return (h1 + h2) + (h3 + h4); + } + + uint32 _hash3(uint32 x) + { + const uint32 h1 = shuffler[((x>> 0)+128)&255]; + const uint32 h2 = shuffler[((x>> 8)+192)&255]; + const uint32 h3 = shuffler[((x>>16)+ 0)&255]; + const uint32 h4 = shuffler[((x>>24)+ 64)&255]; + + return (h1 + h2) * (h3 + h4); + } + + uint32 _hash4(uint32 x) + { + const int i = (x>>24) ^ ((x>>16)&255) ^ ((x>>8)&255) ^ (x&255); + const uint32 h1 = shuffler[i]; + return h1; + } + + long _hashSeeds[256] = { + 76243,172321,123433,222149,99551,197089,147647,247591,87803,184669,135497,234803,111493,209563,159811,260387, + 75527,171583,122651,221401,98849,196271,146917,246773,87149,183917,134777,234083,110731,208787,159119,259531, + 74779,170777,121951,220589,98047,195469,146099,245981,86369,183091,133993,233183,109903,208049,158293,258677, + 74101,170063,121189,219823,97301,194723,145433,245177,85639,182387,133187,232357,109199,207331,157457,257953, + 73369,169321,120551,219071,96497,193861,144593,244411,84919,181669,132499,231481,108499,206483,156727,257141, + 72647,168499,119771,218389,95783,193073,143797,243631,84191,180731,131713,230683,107773,205763,155851,256189, + 71917,167627,119027,217489,95093,192347,142973,242797,83417,179947,130927,229937,106921,205031,155171,255469, + 71261,166909,118213,216757,94397,191599,142159,241981,82633,179269,130183,229223,106273,204163,154373,254773, + 67589,162917,114547,212671,90787,187639,138433,238159,79159,175519,126421,225307,102409,200177,150611,250777, + 66947,162209,113749,211789,90023,186883,137659,237287,78401,174637,125669,224527,101741,199411,149893,249853, + 66179,161377,113017,211051,89387,186107,136897,236503,77647,173867,124907,223747,101081,198593,149159,249059, + 65537,160637,112223,210241,88681,185467,136261,235607,76991,173059,124171,222977,100297,197831,148469,248293, + 70571,166151,117503,215899,93601,190807,141461,241313,81967,178561,129419,228511,105491,203363,153589,253879, + 69877,165343,116747,215063,92893,189977,140689,240509,81233,177811,128669,227651,104723,202591,152837,253103, + 69109,164443,115931,214243,92251,189271,139981,239713,80611,176921,127931,226903,104009,201797,152077,252253, + 68351,163729,115279,213467,91493,188483,139273,238897,79861,176237,127247,226099,103231,201011,151391,251473 + }; + + inline long _hash(unsigned long x) + { + return + ( (_hashSeeds[(x>> 0)&255]<<8) + _hashSeeds[(x>> 8)&255] ) + * ( (_hashSeeds[(x>>16)&255]<<8) + _hashSeeds[(x>>24)&255] ) + ; + } +*/ + + uint32 inthash(uint32 key) + { + key += (key << 12); + key ^= (key >> 22); + key += (key << 4); + key ^= (key >> 9); + key += (key << 10); + key ^= (key >> 2); + key += (key << 7); + key ^= (key >> 12); + return key; + } + + /* + uint32 _rotateRight(uint32 x, const int count) + { + const int modCount = count&31; + const unsigned returnValue = (x>>modCount) | (x<<(32-modCount)); + return returnValue; + } + + uint32 _rotateLeft(uint32 x, const int count) + { + const int modCount = count&31; + const unsigned returnValue = (x<>(32-modCount)); + return returnValue; + } + */ +}; + +//=================================================================== + +unsigned long CoordinateHash::hashTuple(float x, float z) +{ + const uint32 ix = (*(uint32 *)&x); + const uint32 iz = (*(uint32 *)&z)^0xa5a5a5a5; + + const uint32 hx = inthash(ix); + const uint32 hz = inthash(iz); + + const uint32 h = inthash(hx^hz); + + return h; +} + +float CoordinateHash::makeFloat(unsigned long hash) +{ + enum { IEEE_FLOAT_BITS=0x3f800000 }; + + const uint32 mask = ~uint32(0xff800000); + + const uint32 maskedHash = (hash + (hash>>9))&mask; + const uint32 iFloat = IEEE_FLOAT_BITS | maskedHash; + const float returnValue = (*(float *)&iFloat) - 1.0f; + + return returnValue; +} + +#if 0 +long CoordinateHash::hashTuple(float x, float z) +{ + const unsigned long ix = (*(unsigned long *)&x)^0x5a5a5a5a; + const unsigned long iz = (*(unsigned long *)&z)^0xa5a5a5a5; + const unsigned long hx = _hash1((ix>>8) | (ix<<24)); + const unsigned long hz = _hash1((iz>>16) | (iz<<16)); + const unsigned long hmix1 = hx^hz; + const unsigned long h = hmix1; + + /* + FastRandomGenerator rngx(hx); + FastRandomGenerator rngz(hz); + const long rnx = rngx.random(); + const long rnz = rngz.random(); + return rnx^rnz; + */ + + return h; +} +#endif +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.h b/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.h new file mode 100644 index 00000000..f01d0645 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/CoordinateHash.h @@ -0,0 +1,29 @@ +//=================================================================== +// +// CoordinateHash.h +// bearhart 6-30-2005 +// +// copyright 2005, Sony Online Entertainment +// +//-- +// +// Class to hash terrain coordinate pairs into good random seeds. +// +//=================================================================== + +#ifndef INCLUDED_CoordinateHash_H +#define INCLUDED_CoordinateHash_H + +//=================================================================== + +class CoordinateHash +{ +public: + static unsigned long hashTuple(float x, float z); + static float makeFloat(unsigned long hash); +}; + +//=================================================================== + +#endif + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.cpp new file mode 100644 index 00000000..41832800 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.cpp @@ -0,0 +1,635 @@ +// +// EnvironmentGroup.cpp +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/EnvironmentGroup.h" + +#include "sharedFile/Iff.h" +#include "sharedTerrain/ColorRamp256.h" + +//------------------------------------------------------------------- +// +// EnvironmentGroup::Info +// +EnvironmentGroup::Info::Info () : + m_familyId(0) +{ +} + +//------------------------------------------------------------------- + +EnvironmentGroup::Info::~Info () +{ +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::Info::getFamilyId() const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::Info::setFamilyId(int const familyId) +{ + DEBUG_WARNING(familyId < 0 || familyId > 255, ("EnvironmentGroup::Info::setFamilyId: familyId %i will be clamped to a uint8", familyId)); + m_familyId = static_cast(familyId); +} + +//------------------------------------------------------------------- +// +// EnvironmentGroup::Family +// +class EnvironmentGroup::Family +{ +private: + + int familyId; + char* name; + PackedRgb color; + + //-- family data + float m_featherClamp; + +private: + + Family (); + Family (const Family& rhs); //lint -esym (754, Family::Family) + Family& operator= (const Family& rhs); //lint -esym (754, Family::operator=) + +public: + + explicit Family (int newFamilyId); + ~Family (); + + int getFamilyId () const; + void setFamilyId (int newId); + + const char* getName () const; + void setName (const char* newName); + + const PackedRgb& getColor () const; + void setColor (const PackedRgb& newColor); + + float getFeatherClamp () const; + void setFeatherClamp (float featherClamp); +}; + +//------------------------------------------------------------------- + +EnvironmentGroup::Family::Family (int newFamilyId) : + familyId (newFamilyId), + name (0), + color (), + m_featherClamp (1.f) +{ +} + +//------------------------------------------------------------------- + +EnvironmentGroup::Family::~Family () +{ + delete [] name; + name = 0; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::Family::setFamilyId (int newFamilyId) +{ + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +const char* EnvironmentGroup::Family::getName () const +{ + return name; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::Family::setName (const char* newName) +{ + if (name) + { + delete [] name; + name = 0; + } + + if (newName) + name = DuplicateString (newName); +} + +//------------------------------------------------------------------- + +const PackedRgb& EnvironmentGroup::Family::getColor () const +{ + return color; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::Family::setColor (const PackedRgb& newColor) +{ + color = newColor; +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::Family::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- +// +// EnvironmentGroup +// +EnvironmentGroup::EnvironmentGroup () : + familyList (), + errorFamilyColor (255, 0, 255) +{ +} + +//------------------------------------------------------------------- + +EnvironmentGroup::~EnvironmentGroup () +{ + //-- delete family list + removeAllFamilies (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::setFamilyId (int familyIndex, int newFamilyId) +{ + familyList [familyIndex]->setFamilyId (newFamilyId); +} + +//------------------------------------------------------------------- + +const EnvironmentGroup::Info EnvironmentGroup::getDefaultEnvironment () const +{ + Info rfgi; + rfgi.setFamilyId(0); + + return rfgi; +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::findFamilyIndex (int familyId) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getFamilyId () == familyId) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::findFamilyIndex (const PackedRgb& desiredColor) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getColor () == desiredColor) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::removeAllFamilies () +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + { + delete familyList [i]; + familyList [i] = 0; + } + + familyList.clear (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::addFamily (int familyId, const char* name, const PackedRgb& color) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex != -1, ("family with id %i already exists", familyId)); + + if (familyIndex == -1) //lint !e774 //-- if always true + { + Family* family = new Family (familyId); + family->setColor (color); + family->setName (name); + familyList.add (family); + } //lint !e429 //-- family not freed or returned +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::removeFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + delete familyList [familyIndex]; + familyList [familyIndex] = 0; + + familyList.removeIndexAndCompactList (familyIndex); +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::getNumberOfFamilies () const +{ + return familyList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +const EnvironmentGroup::Info EnvironmentGroup::chooseEnvironment (int familyId) const +{ + Info rfgi = getDefaultEnvironment (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + rfgi.setFamilyId(familyId); + else + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("EnvironmentGroup::chooseEnvironment - familyId %i not found, using default shader\n", familyId)); + + return rfgi; +} + +//------------------------------------------------------------------- + +const EnvironmentGroup::Info EnvironmentGroup::chooseEnvironment (const PackedRgb& desiredColor) const +{ + Info rfgi = getDefaultEnvironment (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + rfgi.setFamilyId(familyList[familyIndex]->getFamilyId()); + else + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("EnvironmentGroup::chooseEnvironment - family with color %i %i %i not found, using default shader\n", desiredColor.r, desiredColor.g, desiredColor.b)); + + return rfgi; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::load (Iff& iff) +{ + //-- delete family list first + removeAllFamilies (); + + //-- load data + if (iff.enterForm (TAG (E,G,R,P), true)) + { + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + default: + DEBUG_FATAL (true, ("EnvironmentGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG (E,F,A,M)); + + iff.enterChunk (TAG_DATA); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("EnvironmentGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + char* nameBuffer = iff.read_string (); + family->setName (nameBuffer); + delete [] nameBuffer; + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setFeatherClamp (iff.read_float ()); + + iff.exitChunk (true); + + familyList.add (family); + + iff.exitForm (true); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG (E,F,A,M)); + + iff.enterChunk (TAG_DATA); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("EnvironmentGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + char* nameBuffer = iff.read_string (); + family->setName (nameBuffer); + delete [] nameBuffer; + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setFeatherClamp (iff.read_float ()); + + iff.exitChunk (true); + + familyList.add (family); + + iff.exitForm (true); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG (E,F,A,M)); + + iff.enterChunk (TAG_DATA); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("EnvironmentGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + char* nameBuffer = iff.read_string (); + family->setName (nameBuffer); + delete [] nameBuffer; + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setFeatherClamp (iff.read_float ()); + + iff.exitChunk (true); + + familyList.add (family); + + iff.exitForm (true); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::save (Iff& iff) const +{ + iff.insertForm (TAG (E,G,R,P)); + + iff.insertForm (TAG_0002); + + int numberOfFamilies = getNumberOfFamilies (); + int i; + for (i = 0; i < numberOfFamilies; i++) + { + const Family* family = familyList [i]; + + iff.insertForm (TAG (E,F,A,M)); + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + iff.insertChunkData (static_cast (family->getColor ().r)); + iff.insertChunkData (static_cast (family->getColor ().g)); + iff.insertChunkData (static_cast (family->getColor ().b)); + iff.insertChunkData (family->getFeatherClamp ()); + + iff.exitChunk (TAG_DATA); + iff.exitForm (TAG (E,F,A,M)); + } + + iff.exitForm (TAG_0002); + + iff.exitForm (TAG (E,G,R,P)); +} + +//------------------------------------------------------------------- + +const PackedRgb& EnvironmentGroup::getFamilyColor (int familyId) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + return familyList [familyIndex]->getColor (); + + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("EnvironmentGroup::getFamilyColorById - familyId %i not found, using error color.\n", familyId)); + return errorFamilyColor; +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::getFamilyId (const PackedRgb& desiredColor) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + return familyList [familyIndex]->getFamilyId (); + + //-- color wasn't found, so log and return default shader + return 0; +} + +//------------------------------------------------------------------- + +const char* EnvironmentGroup::getFamilyName (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getName (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::setFamilyName (int familyId, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setName (newName); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::setFamilyColor (int familyId, const PackedRgb& newColor) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setColor (newColor); +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::getFamilyId (int familyIndex) const +{ + return familyList [familyIndex]->getFamilyId (); +} + +//------------------------------------------------------------------- + +bool EnvironmentGroup::hasFamily (int familyId) const +{ + return findFamilyIndex (familyId) != -1; +} + +//------------------------------------------------------------------- + +bool EnvironmentGroup::hasFamily (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return true; + + return false; +} + +//------------------------------------------------------------------- + +int EnvironmentGroup::getFamilyId (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return familyList [i]->getFamilyId (); + + DEBUG_FATAL (true, ("family with name %s not found", name)); + + return -1; //lint !e527 //unreachable +} + +//------------------------------------------------------------------- + +float EnvironmentGroup::Family::getFeatherClamp () const +{ + return m_featherClamp; +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::Family::setFeatherClamp (float featherClamp) +{ + m_featherClamp = featherClamp; +} + +//------------------------------------------------------------------- + +float EnvironmentGroup::getFamilyFeatherClamp (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getFeatherClamp (); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::setFamilyFeatherClamp (int familyId, float featherClamp) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setFeatherClamp (featherClamp); +} + +//------------------------------------------------------------------- + +void EnvironmentGroup::copyFamily (const int destinationFamilyId, const int sourceFamilyId) +{ + setFamilyFeatherClamp (destinationFamilyId, getFamilyFeatherClamp (sourceFamilyId)); +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.h new file mode 100644 index 00000000..31f708ff --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/EnvironmentGroup.h @@ -0,0 +1,115 @@ +//=================================================================== +// +// EnvironmentGroup.h +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_EnvironmentGroup_H +#define INCLUDED_EnvironmentGroup_H + +//=================================================================== + +#include "sharedFoundation/ArrayList.h" +#include "sharedMath/PackedRgb.h" + +class ColorRamp256; +class Iff; + +//=================================================================== + +class EnvironmentGroup +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Info holds info about an environment + // + struct Info + { + public: + + Info(); + ~Info(); + + int getFamilyId() const; + void setFamilyId(int familyId); + + private: + + uint8 m_familyId; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + class Family; + +private: + + //-- list of families + ArrayList familyList; + + //-- + PackedRgb errorFamilyColor; + +private: + + int findFamilyIndex (int familyId) const; + int findFamilyIndex (const PackedRgb& desiredColor) const; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + +private: + + EnvironmentGroup (const EnvironmentGroup& rhs); + EnvironmentGroup& operator= (const EnvironmentGroup& rhs); + +public: + + EnvironmentGroup (); + ~EnvironmentGroup (); + + const Info getDefaultEnvironment () const; + const Info chooseEnvironment (int familyId) const; + const Info chooseEnvironment (const PackedRgb& desiredColor) const; + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void removeAllFamilies (); + + //-- family id routines + void addFamily (int familyId, const char* name, const PackedRgb& color); + void removeFamily (int familyId); + bool hasFamily (int familyId) const; + bool hasFamily (const char* name) const; + + int getFamilyId (const PackedRgb& desiredColor) const; + int getFamilyId (const char* name) const; + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + const PackedRgb& getFamilyColor (int familyId) const; + void setFamilyColor (int familyId, const PackedRgb& prgb); + float getFamilyFeatherClamp (int familyId) const; + void setFamilyFeatherClamp (int familyId, float featherClamp); + + void copyFamily (int destinationFamilyId, int sourceFamilyId); + + //-- family index routines + int getNumberOfFamilies () const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FastKeyList.h b/engine/shared/library/sharedTerrain/src/shared/generator/FastKeyList.h new file mode 100644 index 00000000..aa465b8f --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FastKeyList.h @@ -0,0 +1,133 @@ +//=================================================================== +// +// FastKeyList.h +// asommers +// +// copyright 2001, sony online entertainment +// +//-- +// +// FastKeyList is a sorted automatic memory based list completely avoiding memory allocation +// T must have a .key parameter which is of type KEY + +//=================================================================== + +#ifndef INCLUDED_FastKeyList_H +#define INCLUDED_FastKeyList_H + +//=================================================================== + +template +class FastKeyList +{ +public: + + FastKeyList (); + ~FastKeyList (); + + int getNumberOfElements (); + const T& operator[] (int index) const; + + void insertIfNotExists (const T& element); + +private: + + void add (const T& element); + +private: + + //-- disable heap'ed FastKeyList + void* operator new (size_t size); + + FastKeyList (const FastKeyList& rhs); + FastKeyList& operator= (const FastKeyList& rhs); + +private: + + int numberOfElements; + T data [MAXSIZE]; +}; + +//=================================================================== + +template +inline FastKeyList::FastKeyList () : + numberOfElements (0) +{ +} + +//------------------------------------------------------------------- + +template +inline FastKeyList::~FastKeyList () +{ +} + +//------------------------------------------------------------------- + +template +inline int FastKeyList::getNumberOfElements () +{ + return numberOfElements; +} + +//------------------------------------------------------------------- + +template +inline const T& FastKeyList::operator[] (int index) const +{ + DEBUG_FATAL (index < 0 || index >= numberOfElements, ("index out of range")); + return data [index]; +} + +//------------------------------------------------------------------- + +template +inline void FastKeyList::add (const T& element) +{ + DEBUG_FATAL (numberOfElements == MAXSIZE, ("can't add to a full list")); + + data [numberOfElements++] = element; +} + +//------------------------------------------------------------------- + +template +inline void FastKeyList::insertIfNotExists(const T& element) +{ + //-- search for where to insert + int i = 0; + for (; i < numberOfElements; ++i) + { + if (data[i].key == element.key) + { + return; + } + else if (data[i].key > element.key) + { + break; + } + } + + //-- is element to add at end? + if (i == numberOfElements) + { + add (element); + } + else + { + DEBUG_FATAL (numberOfElements == MAXSIZE, ("can't add to a full list")); + + //-- make room + int j; + for (j = numberOfElements; j >= i; --j) + data [j] = data [j - 1]; + + data [i] = element; + numberOfElements++; + } +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FastList.h b/engine/shared/library/sharedTerrain/src/shared/generator/FastList.h new file mode 100644 index 00000000..1cc45dd7 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FastList.h @@ -0,0 +1,125 @@ +//=================================================================== +// +// FastList.h +// asommers +// +// copyright 2001, sony online entertainment +// +//-- +// +// FastList is an unsorted automatic memory based list completely avoiding memory allocation +// +//=================================================================== + +#ifndef INCLUDED_FastList_H +#define INCLUDED_FastList_H + +//=================================================================== + +template +class FastList +{ +public: + + FastList (); + ~FastList (); + + int getNumberOfElements (); + const T& operator[] (int index) const; + T& operator[] (int index); + + bool exists (const T& element) const; + + void add (const T& element); + void addIfNotExists (const T& element); + +private: + + //-- disable heap'ed fastlist + void* operator new (size_t size); + + FastList (const FastList& rhs); + FastList& operator= (const FastList& rhs); + +private: + + int numberOfElements; + T data [n]; +}; + +//=================================================================== + +template +inline FastList::FastList () : + numberOfElements (0) +{ +} + +//------------------------------------------------------------------- + +template +inline FastList::~FastList () +{ +} + +//------------------------------------------------------------------- + +template +inline int FastList::getNumberOfElements () +{ + return numberOfElements; +} + +//------------------------------------------------------------------- + +template +inline const T& FastList::operator[] (int index) const +{ + DEBUG_FATAL (index < 0 || index >= numberOfElements, ("index out of range")); + return data [index]; +} + +//------------------------------------------------------------------- + +template +inline T& FastList::operator[] (int index) +{ + DEBUG_FATAL (index < 0 || index >= numberOfElements, ("index out of range")); + return data [index]; +} + +//------------------------------------------------------------------- + +template +inline bool FastList::exists (const T& element) const +{ + int i; + for (i = 0; i < numberOfElements; ++i) + if (data [i] == element) + return true; + + return false; +} + +//------------------------------------------------------------------- + +template +inline void FastList::add (const T& element) +{ + DEBUG_FATAL (numberOfElements == n, ("can't add to a full list")); + + data [numberOfElements++] = element; +} + +//------------------------------------------------------------------- + +template +inline void FastList::addIfNotExists (const T& element) +{ + if (!exists (element)) + add (element); +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Feather.h b/engine/shared/library/sharedTerrain/src/shared/generator/Feather.h new file mode 100644 index 00000000..56d9861c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Feather.h @@ -0,0 +1,112 @@ +//=================================================================== +// +// Feather.h +// asommers 2001-01-28 +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_Feather_H +#define INCLUDED_Feather_H + +//=================================================================== + +class Feather +{ +public: + + explicit Feather (TerrainGeneratorFeatherFunction newFeatherFunction); + ~Feather (); + + float feather (float start, float end, float t) const; + +private: + + float linear (float start, float end, float t) const; + float easeIn (float start, float end, float t) const; + float easeOut (float start, float end, float t) const; + float easeInOut (float start, float end, float t) const; + +private: + + Feather (); + Feather (const Feather&); + Feather& operator= (const Feather&); + +private: + + const TerrainGeneratorFeatherFunction featherFunction; +}; + +//=================================================================== + +inline Feather::Feather (TerrainGeneratorFeatherFunction newFeatherFunction) : + featherFunction (newFeatherFunction) +{ +} + +//------------------------------------------------------------------- + +inline Feather::~Feather () +{ +} + +//------------------------------------------------------------------- + +inline float Feather::linear (const float start, const float end, const float t) const +{ + return linearInterpolate (start, end, t); +} + +//------------------------------------------------------------------- + +inline float Feather::easeIn (const float start, const float end, const float t) const +{ + return linearInterpolate (start, end, sqr (t)); +} + +//------------------------------------------------------------------- + +inline float Feather::easeOut (const float start, const float end, const float t) const +{ + return linearInterpolate (start, end, sqrt (t)); +} + +//------------------------------------------------------------------- + +inline float Feather::easeInOut (const float start, const float end, const float t) const +{ + const float a = ((3.0f - (2.0f * t)) * t * t); + + return linearInterpolate (start, end, a); +} + +//------------------------------------------------------------------- + +inline float Feather::feather (const float start, const float end, const float t) const +{ + switch (featherFunction) + { + case TGFF_linear: + return linear (start, end, t); + + case TGFF_easeIn: + return easeIn (start, end, t); + + case TGFF_easeOut: + return easeOut (start, end, t); + + case TGFF_easeInOut: + return easeInOut (start, end, t); + + case TGFF_COUNT: + default: + DEBUG_FATAL (true, ("invalid feather function")); + return 0.0f; //lint !e527 //unreachable + } +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Filter.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/Filter.cpp new file mode 100644 index 00000000..27d89a21 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Filter.cpp @@ -0,0 +1,1298 @@ +// +// Filter.cpp +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/Filter.h" + +#include "sharedFile/Iff.h" +#include "sharedFractal/MultiFractal.h" +#include "sharedFractal/MultiFractalReaderWriter.h" +#include "sharedImage/Image.h" + +#include + +//------------------------------------------------------------------- + +static const float ooPI_TIMES_2 = 1.0f / PI_TIMES_2; + +//------------------------------------------------------------------- + +template +inline bool isWithinRange (const T& minValue, const T& value, const T& maxValue) +{ + return value >= minValue && value <= maxValue; +} + +//------------------------------------------------------------------- + +inline float computeFeatheredInterpolant (const float minimum, const float value, const float maximum, const float featherIn) +{ + if (!WithinRangeExclusiveExclusive (minimum, value, maximum)) + { + return 0.f; + } + + const float feather = featherIn * (maximum - minimum) * 0.5f; + + if (value < minimum + feather) + { + return (value - minimum) / feather; + } + else + if (value > maximum - feather) + { + return (maximum - value) / feather; + } + + return 1.f; +} + +//------------------------------------------------------------------- +// +// FilterHeight +// +FilterHeight::FilterHeight () : + TerrainGenerator::Filter (TAG_FHGT, TGFT_height), + lowHeight (0), + highHeight (0) +{ +} + +//------------------------------------------------------------------- + +FilterHeight::~FilterHeight () +{ +} + +//------------------------------------------------------------------- + +float FilterHeight::isWithin (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + const float height = generatorChunkData.heightMap->getData (x, z); + + return computeFeatheredInterpolant (lowHeight, height, highHeight, getFeatherDistance ()); +} + +//------------------------------------------------------------------- + +void FilterHeight::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void FilterHeight::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + lowHeight = iff.read_float (); + highHeight = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterHeight::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + float unused = iff.read_float (); + UNREF (unused); + + lowHeight = iff.read_float (); + highHeight = iff.read_float (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void FilterHeight::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + lowHeight = iff.read_float (); + highHeight = iff.read_float (); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void FilterHeight::save (Iff& iff) const +{ + iff.insertForm (TAG_0002); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (lowHeight); + iff.insertChunkData (highHeight); + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void FilterHeight::setLowHeight (float newLowHeight) +{ + lowHeight = newLowHeight; +} + +//------------------------------------------------------------------- + +void FilterHeight::setHighHeight (float newHighHeight) +{ + highHeight = newHighHeight; +} + +//------------------------------------------------------------------- +// +// FilterFractal +// +FilterFractal::FilterFractal () : + TerrainGenerator::Filter (TAG_FFRA, TGFT_fractal), + m_multiFractal (0), + m_cachedFamilyId (-1), + m_familyId (0), + m_scaleY (1), + m_lowFractalLimit (0), + m_highFractalLimit (0) +{ +} + +//------------------------------------------------------------------- + +FilterFractal::~FilterFractal () +{ + m_multiFractal = 0; +} + +//------------------------------------------------------------------- + +float FilterFractal::isWithin (const float worldX, const float worldZ, const int x, const int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + if (m_cachedFamilyId != m_familyId) + { + m_cachedFamilyId = m_familyId; + m_multiFractal = generatorChunkData.fractalGroup->getFamilyMultiFractal (m_familyId); + } + + NOT_NULL (m_multiFractal); + const float fractalHeight = m_scaleY * m_multiFractal->getValueCache (worldX, worldZ, x, z); + + return computeFeatheredInterpolant (m_lowFractalLimit, fractalHeight, m_highFractalLimit, getFeatherDistance ()); +} + +//------------------------------------------------------------------- + +void FilterFractal::load (Iff& iff, FractalGroup& fractalGroup) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff, fractalGroup); + break; + + case TAG_0001: + load_0001 (iff, fractalGroup); + break; + + case TAG_0002: + load_0002 (iff, fractalGroup); + break; + + case TAG_0003: + load_0003 (iff, fractalGroup); + break; + + case TAG_0004: + load_0004 (iff, fractalGroup); + break; + + case TAG_0005: + load_0005 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0000 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + const Vector scale = iff.read_floatVector (); + multiFractal.setScale (scale.x, scale.z); + setScaleY (scale.y); + + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0001 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + multiFractal.setNumberOfOctaves (iff.read_int32 ()); + multiFractal.setFrequency (iff.read_float ()); + + Vector scale; + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + const int unused = iff.read_int32 (); + UNREF (unused); + scale.x = iff.read_float (); + scale.z = iff.read_float (); + } + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + for (i = 0; i < multiFractal.getNumberOfOctaves (); i++) + { + const int dummy1 = iff.read_int32 (); + UNREF (dummy1); + + const int dummy2 = iff.read_int32 (); + UNREF (dummy2); + } + + setScaleY (iff.read_float ()); + + multiFractal.setScale (scale.x, scale.z); + + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0002 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + { + float unused = iff.read_float (); + UNREF (unused); + } + + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + multiFractal.setNumberOfOctaves (iff.read_int32 ()); + multiFractal.setFrequency (iff.read_float ()); + + Vector scale; + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + const int unused = iff.read_int32 (); + UNREF (unused); + scale.x = iff.read_float (); + scale.z = iff.read_float (); + } + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + for (i = 0; i < multiFractal.getNumberOfOctaves (); i++) + { + const int dummy1 = iff.read_int32 (); + UNREF (dummy1); + + const int dummy2 = iff.read_int32 (); + UNREF (dummy2); + } + + setScaleY (iff.read_float ()); + + multiFractal.setScale (scale.x, scale.z); + + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0003 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + MultiFractal multiFractal; + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + + const int fractalType = iff.read_int32 (); + DEBUG_FATAL (fractalType < 0 || fractalType >= MultiFractal::CR_COUNT, ("fractal type out of range (%i >= %i", fractalType, MultiFractal::CR_COUNT)); + multiFractal.setCombinationRule (static_cast (fractalType)); + + multiFractal.setNumberOfOctaves (iff.read_int32 ()); + multiFractal.setFrequency (iff.read_float ()); + + Vector scale; + + const int n = iff.read_int32 (); + int i; + for (i = 0; i < n; i++) + { + const int unused = iff.read_int32 (); + UNREF (unused); + scale.x = iff.read_float (); + scale.z = iff.read_float (); + } + + const uint32 seed = iff.read_uint32 (); + multiFractal.setSeed (seed); + + for (i = 0; i < multiFractal.getNumberOfOctaves (); i++) + { + const int dummy1 = iff.read_int32 (); + UNREF (dummy1); + + const int dummy2 = iff.read_int32 (); + UNREF (dummy2); + } + + setScaleY (iff.read_float ()); + + multiFractal.setScale (scale.x, scale.z); + + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0004 (Iff& iff, FractalGroup& fractalGroup) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load the fractal settings + MultiFractal multiFractal; + MultiFractalReaderWriter::load (iff, multiFractal); + setFamilyId (fractalGroup.createFamily (&multiFractal, getName ())); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (clamp (0.f, iff.read_float (), 1.f)); + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + setScaleY (iff.read_float ()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void FilterFractal::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (clamp (0.f, iff.read_float (), 1.f)); + setLowFractalLimit (iff.read_float ()); + setHighFractalLimit (iff.read_float ()); + setScaleY (iff.read_float ()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0005); +} + +//------------------------------------------------------------------- + +void FilterFractal::save (Iff& iff) const +{ + iff.insertForm (TAG_0005); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + iff.insertChunk (TAG (P,A,R,M)); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (getLowFractalLimit ()); + iff.insertChunkData (getHighFractalLimit ()); + iff.insertChunkData (getScaleY ()); + + iff.exitChunk (); + + iff.exitForm (); + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FilterFractal::setFamilyId (const int newFamilyId) +{ + m_familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void FilterFractal::setScaleY (const float newScale) +{ + m_scaleY = newScale; +} + +//------------------------------------------------------------------- + +void FilterFractal::setLowFractalLimit (const float newLowFractalLimit) +{ + m_lowFractalLimit = newLowFractalLimit; +} + +//------------------------------------------------------------------- + +void FilterFractal::setHighFractalLimit (const float newHighFractalLimit) +{ + m_highFractalLimit = newHighFractalLimit; +} + +//------------------------------------------------------------------- +// +// FilterSlope +// +FilterSlope::FilterSlope () : + TerrainGenerator::Filter (TAG_FSLP, TGFT_slope), + maximumAngle (0), + minimumAngle (0), + sinMaxAngle (0), + sinMinAngle (0) +{ + setMinimumAngle (0.f); + setMaximumAngle (0.f); +} + +//------------------------------------------------------------------- + +FilterSlope::~FilterSlope () +{ +} + +//------------------------------------------------------------------- + +float FilterSlope::isWithin (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + const float normalY = generatorChunkData.vertexNormalMap->getData (x, z).y; + + return computeFeatheredInterpolant (sinMaxAngle, normalY, sinMinAngle, getFeatherDistance ()); +} + +//------------------------------------------------------------------- + +void FilterSlope::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void FilterSlope::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setMinimumAngle (convertDegreesToRadians (iff.read_float ())); + setMaximumAngle (convertDegreesToRadians (iff.read_float ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterSlope::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + float unused = iff.read_float (); + UNREF (unused); + + setMinimumAngle (convertDegreesToRadians (iff.read_float ())); + setMaximumAngle (convertDegreesToRadians (iff.read_float ())); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void FilterSlope::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setMinimumAngle (convertDegreesToRadians (iff.read_float ())); + setMaximumAngle (convertDegreesToRadians (iff.read_float ())); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void FilterSlope::save (Iff& iff) const +{ + iff.insertForm (TAG_0002); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (convertRadiansToDegrees (minimumAngle)); + iff.insertChunkData (convertRadiansToDegrees (maximumAngle)); + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void FilterSlope::setMinimumAngle (const float newMinimumAngle) +{ + minimumAngle = clamp (0.f, newMinimumAngle, PI_OVER_2); + + sinMinAngle = sin (PI_OVER_2 - minimumAngle); +} + +//------------------------------------------------------------------- + +void FilterSlope::setMaximumAngle (const float newMaximumAngle) +{ + maximumAngle = clamp (0.f, newMaximumAngle, PI_OVER_2); + + sinMaxAngle = sin (PI_OVER_2 - maximumAngle); +} + +//----------------------------------------------------------------- + +bool FilterSlope::needsNormals () const +{ + return true; +} + +//------------------------------------------------------------------- +// +// FilterDirection +// +FilterDirection::FilterDirection () : + TerrainGenerator::Filter (TAG_FDIR, TGFT_direction), + maximumAngle (0), + minimumAngle (0), + maximumFeatherAngle (0), + minimumFeatherAngle (0) +{ +} + +//------------------------------------------------------------------- + +FilterDirection::~FilterDirection () +{ +} + +//------------------------------------------------------------------- + +float FilterDirection::isWithin (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + const float normalizedTheta = generatorChunkData.vertexNormalMap->getData (x, z).theta () * ooPI_TIMES_2 + 0.5f; + + if (!isWithinRange (minimumFeatherAngle, normalizedTheta, maximumFeatherAngle)) + return 0.f; + + const float featherAngle = (maximumFeatherAngle - minimumFeatherAngle) * getFeatherDistance () * 0.5f; + + if (isWithinRange (minimumFeatherAngle + featherAngle, normalizedTheta, maximumFeatherAngle - featherAngle)) + return 1.f; + + const float maxAngle = maximumFeatherAngle - normalizedTheta; + const float minAngle = normalizedTheta - minimumFeatherAngle; + + float angle = featherAngle; + + if (maxAngle < angle) + angle = maxAngle; + + if (minAngle < angle) + angle = minAngle; + + return angle / featherAngle; +} + +//------------------------------------------------------------------- + +void FilterDirection::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void FilterDirection::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + setMinimumAngle (convertDegreesToRadians (iff.read_float ())); + setMaximumAngle (convertDegreesToRadians (iff.read_float ())); + + setFeatherFunction (static_cast (iff.read_int32 ())); + + const float newFeatherDistance = clamp (0.f, iff.read_float (), 1.f); + setFeatherDistance (newFeatherDistance); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterDirection::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (convertRadiansToDegrees (minimumAngle)); + iff.insertChunkData (convertRadiansToDegrees (maximumAngle)); + + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterDirection::setMinimumAngle (float newMinimumAngle) +{ + minimumAngle = std::max (-PI, newMinimumAngle); + + minimumFeatherAngle = minimumAngle * ooPI_TIMES_2; +} + +//------------------------------------------------------------------- + +void FilterDirection::setMaximumAngle (float newMaximumAngle) +{ + maximumAngle = std::min (PI, newMaximumAngle); + + maximumFeatherAngle = maximumAngle * ooPI_TIMES_2; +} + +//----------------------------------------------------------------- + +bool FilterDirection::needsNormals () const +{ + return true; +} + +//------------------------------------------------------------------- +// +// FilterShader +// +FilterShader::FilterShader () : + TerrainGenerator::Filter (TAG_FSHD, TGFT_shader), + familyId (0) +{ +} + +//------------------------------------------------------------------- + +FilterShader::~FilterShader () +{ +} + +//------------------------------------------------------------------- + +void FilterShader::setFamilyId (const int newFamilyId) +{ + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +bool FilterShader::needsShaders () const +{ + return true; +} + +//------------------------------------------------------------------- + +float FilterShader::isWithin (const float /*worldX*/, const float /*worldZ*/, const int x, const int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + ShaderGroup::Info sgi = generatorChunkData.shaderMap->getData (x, z); + + return (sgi.getFamilyId () == familyId) ? 1.f : 0.f; +} + +//------------------------------------------------------------------- + +void FilterShader::load (Iff& iff) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} +//------------------------------------------------------------------- + +void FilterShader::save (Iff& iff) const +{ + iff.insertForm (TAG_0000); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (familyId); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void FilterShader::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterChunk (TAG_DATA); + + familyId = iff.read_int32 (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +//------------------------------------------------------------------- +// +// FilterBitmap +// + +FilterBitmap::FilterBitmap () : + TerrainGenerator::Filter (TAG_FBIT, TGFT_bitmap), + m_familyId (0), + m_lowBitmapLimit (0), + m_highBitmapLimit (0), + m_extent(), + m_gain (0) +{ +} + +//------------------------------------------------------------------- + +FilterBitmap::~FilterBitmap () +{ + +} + +float FilterBitmap::isWithin (const float worldX, const float worldZ, const int /*x*/, const int /*z*/, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const +{ + const Image* image = generatorChunkData.bitmapGroup->getFamilyBitmap(m_familyId); + + if(!image) + { + return 1.0f; + } + + const int imageWidth = image->getWidth(); + const int imageHeight = image->getHeight(); + const int imageStride = image->getStride(); + Rectangle2d rect; + rect.x0 = 0.0f; + rect.y0 = 0.0f; + rect.x1 = m_extent.x1 - m_extent.x0; + rect.y1 = m_extent.y1 - m_extent.y0; + + DEBUG_FATAL((rect.x1 == 0.0f),("FilterBitmap::isWithin: rect.x1 is 0.0f")); + DEBUG_FATAL((rect.y1 == 0.0f),("FilterBitmap::isWithin: rect.y1 is 0.0f")); + + const float scaledWorldX = std::min((worldX - m_extent.x0) * imageWidth/rect.x1,(float)imageWidth - 1.0f); + const float scaledWorldY = std::min((worldZ - m_extent.y0) * imageHeight/rect.y1, (float)imageHeight - 1.0f); + + const int x0 = (int)scaledWorldX; + const int y0 = (int)scaledWorldY; + int x1 = std::min(x0 + 1,imageWidth - 1); + int y1 = std::min(y0 + 1,imageHeight - 1); + + const int indexIntoImage00 = (((imageHeight - 1) - y0) * imageStride) + x0*(imageStride/imageWidth); + const int indexIntoImage10 = (((imageHeight - 1) - y0) * imageStride) + x1*(imageStride/imageWidth); + const int indexIntoImage01 = (((imageHeight - 1) - y1) * imageStride) + x0*(imageStride/imageWidth); + const int indexIntoImage11 = (((imageHeight - 1) - y1) * imageStride) + x1*(imageStride/imageWidth); + + const uint8* data = image->lockReadOnly (); + + const uint8 value00 = data[indexIntoImage00]; + const uint8 value10 = data[indexIntoImage10]; + const uint8 value01 = data[indexIntoImage01]; + const uint8 value11 = data[indexIntoImage11]; + + image->unlock(); + + const float normalizeVal = 1.0f/255.0f; + const float bitmapHeight00 = value00 * normalizeVal; + const float bitmapHeight10 = value10 * normalizeVal; + const float bitmapHeight01 = value01 * normalizeVal; + const float bitmapHeight11 = value11 * normalizeVal; + + float dx1 = scaledWorldX - (int)scaledWorldX; + float dx2 = 1.0f - dx1; + float dy1 = scaledWorldY - (int)scaledWorldY; + float dy2 = 1.0f - dy1; + + float bitmapHeight = bitmapHeight00 * (dx2 * dy2) + + bitmapHeight10 * (dx1 * dy2) + + bitmapHeight01 * (dx2 * dy1) + + bitmapHeight11 * (dx1 * dy1); + + + bitmapHeight += m_gain; + if(bitmapHeight < 0.0f) + { + bitmapHeight = 0.0f; + } + else if(bitmapHeight >= 1.0f) + { + bitmapHeight = 0.99999f; // to get around the upper exclusion check in computeFeatheredInterpolant + } + + return computeFeatheredInterpolant (m_lowBitmapLimit, bitmapHeight, m_highBitmapLimit, getFeatherDistance ()) * bitmapHeight; + + +} + +//------------------------------------------------------------------- + +void FilterBitmap::setExtent(const Rectangle2d& rect) +{ + m_extent = rect; +} + +//------------------------------------------------------------------- + +void FilterBitmap::setFamilyId (const int newFamilyId) +{ + m_familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void FilterBitmap::setLowBitmapLimit (const float newLowBitmapLimit) +{ + m_lowBitmapLimit = newLowBitmapLimit; +} + +//------------------------------------------------------------------- + +void FilterBitmap::setHighBitmapLimit (const float newHighBitmapLimit) +{ + m_highBitmapLimit = newHighBitmapLimit; +} + +//------------------------------------------------------------------- + +void FilterBitmap::setGain (const float newValue) +{ + m_gain = newValue; +} + +//------------------------------------------------------------------- + +void FilterBitmap::load (Iff& iff/*, BitmapGroup& bitmapGroup*/) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +void FilterBitmap::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (clamp (0.f, iff.read_float (), 1.f)); + setLowBitmapLimit (iff.read_float ()); + setHighBitmapLimit (iff.read_float ()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +void FilterBitmap::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + iff.enterForm (TAG_DATA); + + //-- load parameters + iff.enterChunk (TAG_PARM); + + setFamilyId (iff.read_int32 ()); + setFeatherFunction (static_cast (iff.read_int32 ())); + setFeatherDistance (clamp (0.f, iff.read_float (), 1.f)); + setLowBitmapLimit (iff.read_float ()); + setHighBitmapLimit (iff.read_float ()); + setGain (iff.read_float()); + + iff.exitChunk (); + + iff.exitForm (TAG_DATA); + + iff.exitForm (TAG_0001); +} + + + +void FilterBitmap::save (Iff& iff) const +{ + iff.insertForm (TAG_0001); + + //-- save the base + LayerItem::save (iff); + + //-- save specific data + iff.insertForm (TAG_DATA); + + iff.insertChunk (TAG (P,A,R,M)); + + iff.insertChunkData (getFamilyId ()); + iff.insertChunkData (static_cast (getFeatherFunction ())); + iff.insertChunkData (getFeatherDistance ()); + iff.insertChunkData (getLowBitmapLimit ()); + iff.insertChunkData (getHighBitmapLimit ()); + iff.insertChunkData (getGain ()); + + iff.exitChunk (); + + iff.exitForm (); + + iff.exitForm (); +} + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/Filter.h b/engine/shared/library/sharedTerrain/src/shared/generator/Filter.h new file mode 100644 index 00000000..faff51b6 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/Filter.h @@ -0,0 +1,392 @@ +//=================================================================== +// +// Filter.h +// asommers 9-30-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_Filter_H +#define INCLUDED_Filter_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== +// +// FilterHeight +// +class FilterHeight : public TerrainGenerator::Filter +{ +private: + + float lowHeight; + float highHeight; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + +private: + + FilterHeight (const FilterHeight& rhs); + FilterHeight& operator= (const FilterHeight& rhs); + +public: + + FilterHeight (); + virtual ~FilterHeight (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + + float getLowHeight () const; + void setLowHeight (float newLowHeight); + + float getHighHeight () const; + void setHighHeight (float newHighHeight); +}; + +//------------------------------------------------------------------- + +inline float FilterHeight::getLowHeight () const +{ + return lowHeight; +} + +//------------------------------------------------------------------- + +inline float FilterHeight::getHighHeight () const +{ + return highHeight; +} + +//------------------------------------------------------------------- +// +// FilterFractal +// +class FilterFractal : public TerrainGenerator::Filter +{ +private: + + //-- not accessible + mutable const MultiFractal* m_multiFractal; + mutable int m_cachedFamilyId; + + //-- accessible + int m_familyId; + float m_scaleY; + float m_lowFractalLimit; + float m_highFractalLimit; + +private: + + void load_0000 (Iff& iff, FractalGroup& fractalGroup); + void load_0001 (Iff& iff, FractalGroup& fractalGroup); + void load_0002 (Iff& iff, FractalGroup& fractalGroup); + void load_0003 (Iff& iff, FractalGroup& fractalGroup); + void load_0004 (Iff& iff, FractalGroup& fractalGroup); + void load_0005 (Iff& iff); + +private: + + FilterFractal (const FilterFractal& rhs); + FilterFractal& operator= (const FilterFractal& rhs); + +public: + + FilterFractal (); + virtual ~FilterFractal (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff, FractalGroup& fractalGroup); + virtual void save (Iff& iff) const; + + int getFamilyId () const; + void setFamilyId (int id); + + float getScaleY () const; + void setScaleY (float newScaleY); + + float getLowFractalLimit () const; + void setLowFractalLimit (float newLowFractalLimit); + + float getHighFractalLimit () const; + void setHighFractalLimit (float newHighFractalLimit); +}; + +//------------------------------------------------------------------- + +inline int FilterFractal::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline float FilterFractal::getScaleY () const +{ + return m_scaleY; +} + +//------------------------------------------------------------------- + +inline float FilterFractal::getLowFractalLimit () const +{ + return m_lowFractalLimit; +} + +//------------------------------------------------------------------- + +inline float FilterFractal::getHighFractalLimit () const +{ + return m_highFractalLimit; +} + +//------------------------------------------------------------------- +// +// FilterSlope +// +class FilterSlope : public TerrainGenerator::Filter +{ +private: + + //-- accessible + float maximumAngle; + float minimumAngle; + + //-- not accessible + float sinMaxAngle; + float sinMinAngle; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + +private: + + FilterSlope (const FilterSlope& rhs); + FilterSlope& operator= (const FilterSlope& rhs); + +public: + + FilterSlope (); + virtual ~FilterSlope (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool needsNormals () const; + + float getMinimumAngle () const; + void setMinimumAngle (float newMinimumAngle); + + float getMaximumAngle () const; + void setMaximumAngle (float newMaximumAngle); +}; + +//------------------------------------------------------------------- + +inline float FilterSlope::getMinimumAngle () const +{ + return minimumAngle; +} + +//------------------------------------------------------------------- + +inline float FilterSlope::getMaximumAngle () const +{ + return maximumAngle; +} + +//------------------------------------------------------------------- +// +// FilterDirection +// +class FilterDirection : public TerrainGenerator::Filter +{ +private: + + //-- accessible + float maximumAngle; + float minimumAngle; + + //-- inaccessible + float maximumFeatherAngle; + float minimumFeatherAngle; + +private: + + void load_0000 (Iff& iff); + +private: + + FilterDirection (const FilterDirection& rhs); + FilterDirection& operator= (const FilterDirection& rhs); + +public: + + FilterDirection (); + virtual ~FilterDirection (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool needsNormals () const; + + float getMinimumAngle () const; + void setMinimumAngle (float newMinimumAngle); + + float getMaximumAngle () const; + void setMaximumAngle (float newMaximumAngle); +}; + +//------------------------------------------------------------------- + +inline float FilterDirection::getMinimumAngle () const +{ + return minimumAngle; +} + +//------------------------------------------------------------------- + +inline float FilterDirection::getMaximumAngle () const +{ + return maximumAngle; +} + +//------------------------------------------------------------------- +// +// FilterShader +// +class FilterShader : public TerrainGenerator::Filter +{ +private: + + int familyId; + +private: + + void load_0000 (Iff& iff); + +private: + + FilterShader (const FilterShader& rhs); + FilterShader& operator= (const FilterShader& rhs); + +public: + + FilterShader (); + virtual ~FilterShader (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff); + virtual void save (Iff& iff) const; + virtual bool needsShaders () const; + + int getFamilyId () const; + void setFamilyId (int id); +}; + +//------------------------------------------------------------------- + +inline int FilterShader::getFamilyId () const +{ + return familyId; +} + + + + + + + +//------------------------------------------------------------------- +// +// FilterBitmap +// +class BitmapGroup; +class FilterBitmap : public TerrainGenerator::Filter +{ +private: + + int m_familyId; + float m_lowBitmapLimit; + float m_highBitmapLimit; + Rectangle2d m_extent; + + float m_gain; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + +private: + + FilterBitmap (const FilterBitmap& rhs); + FilterBitmap& operator= (const FilterBitmap& rhs); + +public: + + FilterBitmap (); + virtual ~FilterBitmap (); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const TerrainGenerator::GeneratorChunkData& generatorChunkData) const; + virtual void load (Iff& iff/*, BitmapGroup& bitmapGroup*/); + virtual void save (Iff& iff) const; + + int getFamilyId () const; + void setFamilyId (int id); + + float getLowBitmapLimit () const; + void setLowBitmapLimit (float newLowBitmapLimit); + + float getHighBitmapLimit () const; + void setHighBitmapLimit (float newHighBitmapLimit); + + float getGain () const; + void setGain (float newValue); + + void setExtent(const Rectangle2d& rect); + +}; + +//------------------------------------------------------------------- + +inline int FilterBitmap::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +inline float FilterBitmap::getLowBitmapLimit () const +{ + return m_lowBitmapLimit; +} + +//------------------------------------------------------------------- + +inline float FilterBitmap::getHighBitmapLimit () const +{ + return m_highBitmapLimit; +} + +//------------------------------------------------------------------- + +inline float FilterBitmap::getGain () const +{ + return m_gain; +} + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.cpp new file mode 100644 index 00000000..2f69bb9e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.cpp @@ -0,0 +1,1458 @@ +// +// FloraGroup.cpp +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/FloraGroup.h" + +#include "sharedFile/Iff.h" +#include "sharedFile/TreeFile.h" +#include "sharedObject/AppearanceTemplate.h" +#include "sharedUtility/FileName.h" + +// ====================================================================== +// FloraGroupNamespace +// ====================================================================== + +namespace FloraGroupNamespace +{ + FloraGroup::FamilyChildData const ms_defaultFamilyChildData; +} + +using namespace FloraGroupNamespace; + +//------------------------------------------------------------------- +// +// FloraGroup::Info +// +FloraGroup::Info::Info () : + m_familyId (0), + m_childChoice (0) +{ +} + +//------------------------------------------------------------------- + +FloraGroup::Info::~Info () +{ +} + +//------------------------------------------------------------------- + +int FloraGroup::Info::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void FloraGroup::Info::setFamilyId (int const familyId) +{ + m_familyId = static_cast (familyId); +} + +//------------------------------------------------------------------- + +float FloraGroup::Info::getChildChoice () const +{ + return static_cast (m_childChoice) / 255.f; +} + +//------------------------------------------------------------------- + +void FloraGroup::Info::setChildChoice (float childChoice) +{ + m_childChoice = static_cast (childChoice * 255.f); +} + +//------------------------------------------------------------------- +// +// FloraGroup::FamilyChildData +// +FloraGroup::FamilyChildData::FamilyChildData () : + familyId (0), + weight (0.f), + appearanceTemplateName (0), + shouldSway (false), + period (0.1f), + displacement (0.01f), + alignToTerrain (false), + shouldScale (false), + minimumScale (1.f), + maximumScale (1.f) +{ +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData::~FamilyChildData () +{ + appearanceTemplateName = 0; +} + +//------------------------------------------------------------------- +// +// FloraGroup::Family +// +class FloraGroup::Family +{ +private: + + int familyId; + char* name; + PackedRgb color; + + //-- family data + float density; + bool floats; + + //-- child data + mutable ArrayList childList; + +private: + + void removeChild (int childIndex); + +private: + + Family (); + Family (const Family& rhs); //lint -esym(754, Family::Family) + Family& operator= (const Family& rhs); //lint -esym(754, Family::operator=) + +public: + + explicit Family (int newFamilyId); + ~Family (); + + int getNumberOfChildren () const; + FamilyChildData const & getChild(int childIndex) const; + FamilyChildData const & getChild(char const * name) const; + + int createFlora (float randomNumber0To1) const; + + const char* getName () const; + void setName (const char* newName); + + const PackedRgb& getColor () const; + void setColor (const PackedRgb& newColor); + + float getDensity () const; + void setDensity (float newDensity); + + bool getFloats () const; + void setFloats (bool newFloats); + + int getFamilyId () const; + void setFamilyId (int newId); + + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + void setChild (const FamilyChildData& familyChildData); + + void renameChild (const char* oldName, const char* newName); +}; + +//------------------------------------------------------------------- + +FloraGroup::Family::Family (int newFamilyId) : + familyId (newFamilyId), + name (0), + color (), + density (1), + floats (false), + childList () +{ +} + +//------------------------------------------------------------------- + +FloraGroup::Family::~Family () +{ + delete [] name; + name = 0; + + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + removeChild (i); + + childList.clear (); +} + +//------------------------------------------------------------------- + +int FloraGroup::Family::getNumberOfChildren () const +{ + return childList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +const char* FloraGroup::Family::getName () const +{ + return name; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setName (const char* newName) +{ + if (name) + { + delete [] name; + name = 0; + } + + if (newName) + name = DuplicateString (newName); +} + +//------------------------------------------------------------------- + +const PackedRgb& FloraGroup::Family::getColor () const +{ + return color; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setColor (const PackedRgb& newColor) +{ + color = newColor; +} + +//------------------------------------------------------------------- + +int FloraGroup::Family::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setFamilyId (int newFamilyId) +{ + DEBUG_FATAL (familyId < 0 || familyId > 255, ("FloraGroup::Family::setFamilyId [%s]: familyId %i outside the legal range of 0..255", getName (), familyId)); + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::addChild (const FamilyChildData& familyChildData) +{ + DEBUG_FATAL (familyId != familyChildData.familyId, ("adding child to wrong family")); + + //-- add the name, but not the appearance template. those will be loaded when the appearance is actually used + FamilyChildData child = familyChildData; + child.familyId = familyId; + +#if 1 + //-- fixup fubar'ed names for a version + FileName baseName (FileName::P_none, familyChildData.appearanceTemplateName); + baseName.stripPathAndExt (); + + FileName const satName (FileName::P_appearance, baseName, "sat"); + if (TreeFile::exists (satName)) + { + FileName const baseSatName (FileName::P_none, baseName, "sat"); + child.appearanceTemplateName = DuplicateString (baseSatName); + } + else + { + FileName const prtName (FileName::P_appearance, baseName, "prt"); + if (TreeFile::exists (prtName)) + { + FileName const basePrtName (FileName::P_none, baseName, "prt"); + child.appearanceTemplateName = DuplicateString (basePrtName); + } + else + { + FileName const aptName (FileName::P_appearance, baseName, "apt"); + if (TreeFile::exists (aptName)) + { + FileName const baseAptName (FileName::P_none, baseName, "apt"); + child.appearanceTemplateName = DuplicateString (baseAptName); + } + else + child.appearanceTemplateName = DuplicateString (familyChildData.appearanceTemplateName); + } + } +#else + child.appearanceTemplateName = DuplicateString (familyChildData.appearanceTemplateName); +#endif + + childList.add (child); +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::removeChild (int childIndex) +{ + if (childList [childIndex].appearanceTemplateName) + { + delete [] const_cast (childList [childIndex].appearanceTemplateName); + childList [childIndex].appearanceTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::removeChild (const FamilyChildData& familyChildData) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].appearanceTemplateName, familyChildData.appearanceTemplateName) == 0) + break; + + DEBUG_FATAL (i >= childList.getNumberOfElements (), ("child not found")); + + //-- remove child from list + removeChild (i); + childList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::Family::getChild(int const childIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, childIndex, childList.size()); + return childList[childIndex]; +} + +//------------------------------------------------------------------- +// +// FloraGroup +// +FloraGroup::FloraGroup () : + familyList (), + errorFamilyColor (255, 0, 255) +{ +} + +//------------------------------------------------------------------- + +FloraGroup::~FloraGroup () +{ + //-- delete family list + removeAllFamilies (); +} + +//------------------------------------------------------------------- + +int FloraGroup::getFamilyId (int familyIndex) const +{ + return familyList [familyIndex]->getFamilyId (); +} + +//------------------------------------------------------------------- + +int FloraGroup::findFamilyIndex (int familyId) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getFamilyId () == familyId) + return i; + + return -1; +} + +//------------------------------------------------------------------- + +void FloraGroup::removeAllFamilies () +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + { + delete familyList [i]; + familyList [i] = 0; + } + + familyList.clear (); +} + +//------------------------------------------------------------------- + +void FloraGroup::addFamily (int familyId, const char* name, const PackedRgb& color) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex != -1, ("family with id %i already exists", familyId)); + + if (familyIndex == -1) //lint !e774 //-- if is always true + { + Family* family = new Family (familyId); + family->setColor (color); + family->setName (name); + familyList.add (family); + } //lint !e429 //-- family has not been freed or returned +} + +//------------------------------------------------------------------- + +void FloraGroup::removeFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + delete familyList [familyIndex]; + familyList [familyIndex] = 0; + + familyList.removeIndexAndCompactList (familyIndex); +} + +//------------------------------------------------------------------- + +void FloraGroup::addChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->addChild (familyData); +} + +//------------------------------------------------------------------- + +void FloraGroup::removeChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->removeChild (familyData); +} + +//------------------------------------------------------------------- + +int FloraGroup::getNumberOfFamilies () const +{ + return familyList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +int FloraGroup::getNumberOfChildren (int familyIndex) const +{ + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::getChild(int const familyIndex, int const childIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, familyIndex, familyList.size()); + return familyList[familyIndex]->getChild(childIndex); +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::Family::getChild(char const * const childName) const +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].appearanceTemplateName, childName) == 0) + return getChild (i); + + DEBUG_FATAL (true, ("child %s not found", childName)); + return ms_defaultFamilyChildData; +} + +//------------------------------------------------------------------- + +const PackedRgb& FloraGroup::getFamilyColor (int familyId) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + return familyList [familyIndex]->getColor (); + + //-- family id wasn't found, so log and return default appearance + DEBUG_REPORT_LOG_PRINT (true, ("FloraGroup::getFamilyColorById - familyId %i not found, using error color.\n", familyId)); + + return errorFamilyColor; +} + +//------------------------------------------------------------------- + +int FloraGroup::findFamilyIndex (const PackedRgb& desiredColor) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getColor () == desiredColor) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::createFlora(FloraGroup::Info const & fgi) const +{ + int const familyId = fgi.getFamilyId (); + float const childChoice = fgi.getChildChoice (); + DEBUG_FATAL (childChoice < 0.f || childChoice > 1.f, ("FloraGroup::createFlora: childChoice %1.2f out of bounds (0..1)", childChoice)); + + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + return familyList [familyIndex]->getChild (familyList [familyIndex]->createFlora (childChoice)); + + //-- family id wasn't found, so log and return default appearance + DEBUG_REPORT_LOG_PRINT (true, ("FloraGroup::chooseFlora - familyId %i not found, using no appearance\n", familyId)); + return ms_defaultFamilyChildData; +} + +//------------------------------------------------------------------- + +const FloraGroup::Info FloraGroup::chooseFlora (int familyId) const +{ + Info fgi = getDefaultFlora (); + + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + { + fgi.setFamilyId (familyId); + } + else + { + //-- family id wasn't found, so log and return default appearance + DEBUG_REPORT_LOG_PRINT (true, ("FloraGroup::chooseFlora - familyId %i not found, using no appearance\n", familyId)); + } + + return fgi; +} + +//------------------------------------------------------------------- + +const FloraGroup::Info FloraGroup::chooseFlora (const PackedRgb& desiredColor) const +{ + Info fgi = getDefaultFlora (); + + //-- search for the Flora in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + { + fgi.setFamilyId (familyList [familyIndex]->getFamilyId ()); + } + else + { + //-- family id wasn't found, so log and return default Flora + DEBUG_REPORT_LOG_PRINT (true, ("FloraGroup::chooseFlora - family with color %i %i %i not found, using default flora\n", desiredColor.r, desiredColor.g, desiredColor.b)); + } + + return fgi; +} + +//------------------------------------------------------------------- + +void FloraGroup::load (Iff& iff) +{ + //-- delete all old data + removeAllFamilies (); + + //-- load new data + if (iff.enterForm (TAG (F,G,R,P), true)) + { + switch (iff.getCurrentName ()) + { + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + case TAG_0006: + load_0006 (iff); + break; + + case TAG_0007: + load_0007 (iff); + break; + + case TAG_0008: + load_0008 (iff); + break; + + default: + DEBUG_FATAL (true, ("FloraGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + //-- new appearance changes require this addition + strcat (nameBuffer, ".msh"); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + { + const float unused = iff.read_float (); + UNREF (unused); + } + + { + const int32 unused = iff.read_int32 (); + UNREF (unused); + } + + { + const float unused = iff.read_float (); + UNREF (unused); + } + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + //-- new appearance changes require this addition + strcat (nameBuffer, ".msh"); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + { + const float unused = iff.read_float (); + UNREF (unused); + } + + { + const int32 unused = iff.read_int32 (); + UNREF (unused); + } + + { + const float unused = iff.read_float (); + UNREF (unused); + } + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0006 (Iff& iff) +{ + iff.enterForm (TAG_0006); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + family->setFloats (iff.read_int32 () != 0); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0007 (Iff& iff) +{ + iff.enterForm (TAG_0007); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + family->setFloats (iff.read_int32 () != 0); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + const bool alignToTerrain = iff.read_int32 () != 0; + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + fcd.alignToTerrain = alignToTerrain; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::load_0008 (Iff& iff) +{ + iff.enterForm (TAG_0008); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (F,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("FloraGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + family->setFloats (iff.read_int32 () != 0); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + const bool alignToTerrain = iff.read_int32 () != 0; + const bool shouldScale = iff.read_int32 () != 0; + const float minimumScale = iff.read_float (); + const float maximumScale = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.appearanceTemplateName = nameBuffer; + fcd.weight = weight; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + fcd.alignToTerrain = alignToTerrain; + fcd.shouldScale = shouldScale; + fcd.minimumScale = minimumScale; + fcd.maximumScale = maximumScale; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family has not been freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FloraGroup::save (Iff& iff) const +{ + iff.insertForm (TAG (F,G,R,P)); + + iff.insertForm (TAG_0008); + + int numberOfFamilies = getNumberOfFamilies (); + int i; + for (i = 0; i < numberOfFamilies; i++) + { + const Family* family = familyList [i]; + + iff.insertChunk (TAG (F,F,A,M)); + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + iff.insertChunkData (static_cast (family->getColor ().r)); + iff.insertChunkData (static_cast (family->getColor ().g)); + iff.insertChunkData (static_cast (family->getColor ().b)); + iff.insertChunkData (family->getDensity ()); + iff.insertChunkData (family->getFloats () ? static_cast (1) : static_cast (0)); + + int numberOfChildren = getNumberOfChildren (i); + iff.insertChunkData (numberOfChildren); + + int j; + for (j = 0; j < numberOfChildren; j++) + { + const FamilyChildData fcd = getChild (i, j); + + iff.insertChunkString (fcd.appearanceTemplateName); + iff.insertChunkData (fcd.weight); + iff.insertChunkData (fcd.shouldSway ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.displacement); + iff.insertChunkData (fcd.period); + iff.insertChunkData (fcd.alignToTerrain ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.shouldScale ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.minimumScale); + iff.insertChunkData (fcd.maximumScale); + } + + iff.exitChunk (TAG (F,F,A,M)); + } + + iff.exitForm (TAG_0008); + + iff.exitForm (TAG (F,G,R,P)); +} + +//------------------------------------------------------------------- + +int FloraGroup::getFamilyId (const PackedRgb& desiredColor) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + return familyList [familyIndex]->getFamilyId (); + + //-- color wasn't found, so log and return default flora + return 0; +} + +//------------------------------------------------------------------- + +int FloraGroup::getFamilyNumberOfChildren (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::getFamilyChild(int const familyId, int const childIndex) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return getChild (familyIndex, childIndex); +} + +//------------------------------------------------------------------- + +FloraGroup::FamilyChildData const & FloraGroup::getFamilyChild(int const familyId, char const * const childName) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getChild (childName); +} + +//------------------------------------------------------------------- + +const char* FloraGroup::getFamilyName (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getName (); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyName (int familyId, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setName (newName); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyColor (int familyId, const PackedRgb& newColor) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setColor (newColor); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyId (int familyIndex, int newFamilyId) +{ + familyList [familyIndex]->setFamilyId (newFamilyId); +} + +//------------------------------------------------------------------- + +const FloraGroup::Info FloraGroup::getDefaultFlora () const +{ + return Info (); +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::renameChild (const char* oldName, const char* newName) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].appearanceTemplateName, oldName) == 0) + { + //-- delete the name + delete [] const_cast (childList [i].appearanceTemplateName); + + //-- rename the child + childList [i].appearanceTemplateName = DuplicateString (newName); + } +} + +//------------------------------------------------------------------- + +void FloraGroup::renameChild (int familyId, const char* oldName, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->renameChild (oldName, newName); +} + +//------------------------------------------------------------------- + +int FloraGroup::Family::createFlora (float randomNumber0To1) const +{ + DEBUG_FATAL ((randomNumber0To1 < 0.f || randomNumber0To1 > 1.f), ("Random number out of bounds: %g", randomNumber0To1)); + + float weightSum = 0.f; + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + weightSum += childList[i].weight; + + float randomNumber = randomNumber0To1 * weightSum; + + int radialIndex = 0; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (randomNumber <= childList[i].weight) + { + radialIndex = i; + break; + } + else + randomNumber -= childList[i].weight; + } + + return radialIndex; +} + +//------------------------------------------------------------------- + +bool FloraGroup::hasFamily (int familyId) const +{ + return findFamilyIndex (familyId) != -1; +} + +//------------------------------------------------------------------- + +bool FloraGroup::hasFamily (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return true; + + return false; +} + +//------------------------------------------------------------------- + +int FloraGroup::getFamilyId (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return familyList [i]->getFamilyId (); + + DEBUG_FATAL (true, ("family with name %s not found", name)); + + return -1; //lint !e527 //unreachable +} + +//------------------------------------------------------------------- + +float FloraGroup::Family::getDensity () const +{ + return density; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setDensity (float newDensity) +{ + density = newDensity; +} + +//------------------------------------------------------------------- + +float FloraGroup::getFamilyDensity (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getDensity (); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyDensity (int familyId, float density) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setDensity (density); +} + +//------------------------------------------------------------------- + +bool FloraGroup::Family::getFloats () const +{ + return floats; +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setFloats (bool newFloats) +{ + floats = newFloats; +} + +//------------------------------------------------------------------- + +bool FloraGroup::getFamilyFloats (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getFloats (); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyFloats (int familyId, bool floats) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setFloats (floats); +} + +//------------------------------------------------------------------- + +void FloraGroup::Family::setChild (const FamilyChildData& familyChildData) +{ + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (strcmp (familyChildData.appearanceTemplateName, childList [i].appearanceTemplateName) == 0) + { + const char* appearanceTemplateName = childList [i].appearanceTemplateName; + + childList [i] = familyChildData; + childList [i].appearanceTemplateName = appearanceTemplateName; + + return; + } + } + + DEBUG_FATAL (true, ("child %s not found in family", familyChildData.appearanceTemplateName)); +} + +//------------------------------------------------------------------- + +void FloraGroup::setFamilyChild (int familyId, const FamilyChildData& familyChildData) +{ + const int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setChild (familyChildData); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.h new file mode 100644 index 00000000..3cb000f8 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FloraGroup.h @@ -0,0 +1,167 @@ +//=================================================================== +// +// FloraGroup.h +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//-- +// +// A FloraGroup contains lists of families of meshes organized by id. +// A flora family is a list of valid appearances for a specified id. The flora +// family also stores the name of the flora, and its appearanceTemplate. +// The flora group will return created appearances for use with the terrain +// system. In the event that requested flora family id does not +// exist, the flora group will return a [clearly visible] default flora. +// Families will only create flora when they are chosen. +// +//=================================================================== + +#ifndef FLORAGROUP_H +#define FLORAGROUP_H + +//=================================================================== + +#include "sharedFoundation/ArrayList.h" +#include "sharedMath/PackedRgb.h" + +class Iff; +class AppearanceTemplate; + +//=================================================================== + +class FloraGroup +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Info holds info about flora for the flora map + // + struct Info + { + public: + + Info (); + ~Info (); + + int getFamilyId () const; + void setFamilyId (int familyId); + float getChildChoice () const; + void setChildChoice (float childChoice); + + private: + + uint8 m_familyId; + uint8 m_childChoice; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // FamilyChildData allows creation of FloraGroups + // + struct FamilyChildData + { + public: + + int familyId; + float weight; + const char* appearanceTemplateName; + bool shouldSway; + float period; + float displacement; + bool alignToTerrain; + bool shouldScale; + float minimumScale; + float maximumScale; + + public: + + FamilyChildData (); + ~FamilyChildData (); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + class Family; + +private: + + //-- list of families + ArrayList familyList; + + //-- + PackedRgb errorFamilyColor; + +private: + + int findFamilyIndex (int familyId) const; + int findFamilyIndex (const PackedRgb& desiredColor) const; + + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + void load_0006 (Iff& iff); + void load_0007 (Iff& iff); + void load_0008 (Iff& iff); + +private: + + FloraGroup (const FloraGroup& rhs); + FloraGroup& operator= (const FloraGroup& rhs); + +public: + + FloraGroup (); + ~FloraGroup (); + + const Info getDefaultFlora () const; + const Info chooseFlora (int familyId) const; + const Info chooseFlora (const PackedRgb& desiredColor) const; + + FamilyChildData const & createFlora(FloraGroup::Info const & rfgi) const; + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void removeAllFamilies (); + + //-- family id routines + void addFamily (int familyId, const char* name, const PackedRgb& color); + void removeFamily (int familyId); + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + bool hasFamily (int familyId) const; + bool hasFamily (const char* name) const; + + int getFamilyId (const PackedRgb& desiredColor) const; + int getFamilyId (const char* name) const; + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + const PackedRgb& getFamilyColor (int familyId) const; + void setFamilyColor (int familyId, const PackedRgb& prgb); + int getFamilyNumberOfChildren (int familyId) const; + void renameChild (int familyId, const char* oldName, const char* newName); + FamilyChildData const & getFamilyChild(int familyId, char const * childName) const; + FamilyChildData const & getFamilyChild(int familyId, int childIndex) const; + void setFamilyChild (int familyId, const FamilyChildData& familyChildData); + float getFamilyDensity (int familyId) const; + void setFamilyDensity (int familyId, float density); + bool getFamilyFloats (int familyId) const; + void setFamilyFloats (int familyId, bool floats); + + //-- family index routines + int getNumberOfFamilies () const; + int getNumberOfChildren (int familyIndex) const; + FamilyChildData const & getChild(int familyIndex, int childIndex) const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.cpp new file mode 100644 index 00000000..3857391f --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.cpp @@ -0,0 +1,478 @@ +//=================================================================== +// +// FractalGroup.cpp +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/FractalGroup.h" + +#include "sharedFile/Iff.h" +#include "sharedFractal/MultiFractal.h" +#include "sharedFractal/MultiFractalReaderWriter.h" + +#include +#include +#include + +//=================================================================== + +namespace +{ + const Tag TAG_MGRP = TAG (M,G,R,P); + const Tag TAG_MFAM = TAG (M,F,A,M); +} + +//=================================================================== +// +// FractalGroup::Family +// +class FractalGroup::Family +{ +public: + + explicit Family (int familyId); + ~Family (); + + const char* getName () const; + void setName (const char* name); + + int getFamilyId () const; + void setFamilyId (int familyId); + + const MultiFractal& getMultiFractal () const; + MultiFractal& getMultiFractal (); + +private: + + Family (); + Family (const Family& rhs); //lint -esym (754, Family::Family) + Family& operator= (const Family& rhs); //lint -esym (754, Family::operator=) + +private: + + char* m_name; + int m_familyId; + MultiFractal m_multiFractal; +}; + +//------------------------------------------------------------------- + +FractalGroup::Family::Family (int familyId) : + m_name (0), + m_familyId (familyId), + m_multiFractal () +{ +} + +//------------------------------------------------------------------- + +FractalGroup::Family::~Family () +{ + delete [] m_name; + m_name = 0; +} + +//------------------------------------------------------------------- + +const char* FractalGroup::Family::getName () const +{ + return m_name; +} + +//------------------------------------------------------------------- + +void FractalGroup::Family::setName (const char* name) +{ + if (m_name) + { + delete [] m_name; + m_name = 0; + } + + if (name) + m_name = DuplicateString (name); +} + +//------------------------------------------------------------------- + +int FractalGroup::Family::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void FractalGroup::Family::setFamilyId (int familyId) +{ + m_familyId = familyId; +} + +//------------------------------------------------------------------- + +const MultiFractal& FractalGroup::Family::getMultiFractal () const +{ + return m_multiFractal; +} + +//------------------------------------------------------------------- + +MultiFractal& FractalGroup::Family::getMultiFractal () +{ + return m_multiFractal; //lint !e1536 //-- exposing low access member +} + +//=================================================================== +// +// FractalGroup +// +FractalGroup::FractalGroup () : + m_familyMap (new FamilyMap) +{ +} + +//------------------------------------------------------------------- + +FractalGroup::~FractalGroup () +{ + //-- delete family list + reset (); + + delete m_familyMap; + m_familyMap = 0; +} + +//------------------------------------------------------------------- + +void FractalGroup::load (Iff& iff) +{ + //-- delete family list first + reset (); + + //-- load data + if (iff.enterForm (TAG_MGRP, true)) + { + DEBUG_WARNING (iff.getCurrentName () != TAG_0000, ("FractalGroup::load - loading old version")); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + DEBUG_FATAL (true, ("FractalGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void FractalGroup::save (Iff& iff) const +{ + iff.insertForm (TAG_MGRP); + + iff.insertForm (TAG_0000); + + for (FamilyMap::iterator iter = m_familyMap->begin (); iter != m_familyMap->end (); ++iter) + { + const Family* family = iter->second; + + iff.insertForm (TAG_MFAM); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + + iff.exitChunk (); + + MultiFractalReaderWriter::save (iff, family->getMultiFractal ()); + + iff.exitForm (); + } + + iff.exitForm (); + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void FractalGroup::reset () +{ + for (FamilyMap::iterator iter = m_familyMap->begin (); iter != m_familyMap->end (); ++iter) + delete iter->second; + + m_familyMap->clear (); +} + +//------------------------------------------------------------------- + +void FractalGroup::prepare (int cacheX, int cacheY) +{ + for (FamilyMap::iterator iter = m_familyMap->begin (); iter != m_familyMap->end (); ++iter) + iter->second->getMultiFractal ().allocateCache (cacheX, cacheY); +} + +//------------------------------------------------------------------- + +const char* FractalGroup::getFamilyName (int familyId) const +{ + const Family* const family = getFamily (familyId); + return family->getName (); +} + +//------------------------------------------------------------------- + +void FractalGroup::setFamilyName (int familyId, const char* name) +{ + Family* const family = getFamily (familyId); + family->setName (name); +} + +//------------------------------------------------------------------- + +const MultiFractal* FractalGroup::getFamilyMultiFractal (int familyId) const +{ + const Family* const family = getFamily (familyId); + return &family->getMultiFractal (); +} + +//------------------------------------------------------------------- + +MultiFractal* FractalGroup::getFamilyMultiFractal (int familyId) +{ + Family* const family = getFamily (familyId); + return &family->getMultiFractal (); +} + +//------------------------------------------------------------------- + +void FractalGroup::addFamily (int familyId, const char* name) +{ + DEBUG_FATAL (getFamily (familyId) != 0, ("family with id %i already exists", familyId)); + + Family* family = new Family (familyId); + family->setName (name); + + IGNORE_RETURN (m_familyMap->insert (FamilyMap::value_type (familyId, family))); +} + +//------------------------------------------------------------------- + +void FractalGroup::removeFamily (int familyId) +{ + FamilyMap::iterator iter = m_familyMap->find (familyId); + DEBUG_FATAL (iter == m_familyMap->end (), ("family with id %i not found", familyId)); + + m_familyMap->erase (iter); +} + +//------------------------------------------------------------------- + +bool FractalGroup::hasFamily (int familyId) const +{ + return getFamily (familyId) != 0; +} + +//------------------------------------------------------------------- + +bool FractalGroup::findFamily (const char* name, int& familyId) const +{ + const Family* const family = getFamily (name); + + if (family) + familyId = family->getFamilyId (); + + return family != 0; +} + +//------------------------------------------------------------------- + +int FractalGroup::getNumberOfFamilies () const +{ + return static_cast (m_familyMap->size ()); +} + +//------------------------------------------------------------------- + +const FractalGroup::Family* FractalGroup::getFamily (int familyId) const +{ + FamilyMap::const_iterator iter = m_familyMap->find (familyId); + if (iter != m_familyMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +FractalGroup::Family* FractalGroup::getFamily (int familyId) +{ + FamilyMap::iterator iter = m_familyMap->find (familyId); + if (iter != m_familyMap->end ()) + return iter->second; + + return 0; +} + +//------------------------------------------------------------------- + +const FractalGroup::Family* FractalGroup::getFamily (const char* familyName) const +{ + FamilyMap::iterator iter = m_familyMap->begin (); + for (; iter != m_familyMap->end (); ++iter) + { + const Family* const family = iter->second; + + if (_stricmp (familyName, family->getName ()) == 0) + return family; + } + + return 0; +} + +//------------------------------------------------------------------- + +FractalGroup::Family* FractalGroup::getFamily (const char* familyName) +{ + FamilyMap::iterator iter = m_familyMap->begin (); + for (; iter != m_familyMap->end (); ++iter) + { + Family* const family = iter->second; + + if (_stricmp (familyName, family->getName ()) == 0) + return family; + } + + return 0; +} + +//------------------------------------------------------------------- + +void FractalGroup::setFamilyId (int familyIndex, int familyId) +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, familyIndex, getNumberOfFamilies ()); + + Family* const family = getFamily (familyIndex); + NOT_NULL (family); + family->setFamilyId (familyId); +} + +//------------------------------------------------------------------- + +void FractalGroup::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG_MFAM); + + iff.enterChunk (TAG_DATA); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (getFamily (familyId) != 0, ("EnvironmentGroup::load familyId %i is already in use", familyId)); + + char* nameBuffer = iff.read_string (); + + //-- add family + addFamily (familyId, nameBuffer); + + delete [] nameBuffer; + + iff.exitChunk (); + + Family* const family = getFamily (familyId); + NOT_NULL (family); + MultiFractalReaderWriter::load (iff, family->getMultiFractal ()); + + iff.exitForm (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +int FractalGroup::getFamilyId (int familyIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE (0, familyIndex, static_cast (m_familyMap->size ())); + + FamilyMap::iterator iter = m_familyMap->begin (); + int i = 0; + for (; i < familyIndex || iter == m_familyMap->end (); ++i, ++iter) + ; + + DEBUG_FATAL (iter == m_familyMap->end (), ("")); + return iter->second->getFamilyId (); +} + +//------------------------------------------------------------------- + +int FractalGroup::createFamily (const MultiFractal* multiFractal, const char* baseName) +{ + NOT_NULL (multiFractal); + + FamilyMap::iterator iter = m_familyMap->begin (); + for (; iter != m_familyMap->end (); ++iter) + { + const Family* const family = iter->second; + + if (family->getMultiFractal () == *multiFractal) + return family->getFamilyId (); + } + + const int familyId = createUniqueFamilyId (); + std::string familyName = createUniqueFamilyName (baseName); + + addFamily (familyId, familyName.c_str ()); + + Family* const family = getFamily (familyId); + NOT_NULL (family); + family->getMultiFractal () = *multiFractal; + + return familyId; +} + +//------------------------------------------------------------------- + +int FractalGroup::createUniqueFamilyId () const +{ + int familyId = 1; + + while (getFamily (familyId) != 0) + ++familyId; + + return familyId; +} + +//------------------------------------------------------------------- + +std::string FractalGroup::createUniqueFamilyName (const char* baseName) const +{ + char familyName [1000]; + int i = 0; + + do + { + ++i; + + sprintf (familyName, "%s_%i", baseName, i); + } + while (getFamily (familyName) != 0); + + return std::string (familyName); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.h new file mode 100644 index 00000000..35d017c6 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/FractalGroup.h @@ -0,0 +1,81 @@ +//=================================================================== +// +// FractalGroup.h +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_FractalGroup_H +#define INCLUDED_FractalGroup_H + +//=================================================================== + +class Iff; +class MultiFractal; + +//=================================================================== + +class FractalGroup +{ +public: + + FractalGroup (); + ~FractalGroup (); + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void reset (); + + void prepare (int cacheX, int cacheY); + + //-- + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + const MultiFractal* getFamilyMultiFractal (int familyId) const; + MultiFractal* getFamilyMultiFractal (int familyId); + + //-- family id routines + void addFamily (int familyId, const char* name); + void removeFamily (int familyId); + bool hasFamily (int familyId) const; + bool findFamily (const char* name, int& familyId) const; + + //-- family index routines + int getNumberOfFamilies () const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); + + //-- used to convert from the old terrain format to the new terrain format + int createFamily (const MultiFractal* multiFractal, const char* baseName); + +private: + + //-- list of families + class Family; + typedef stdmap::fwd FamilyMap; + FamilyMap* m_familyMap; + +private: + + const Family* getFamily (int familyId) const; + Family* getFamily (int familyId); + const Family* getFamily (const char* familyName) const; + Family* getFamily (const char* familyName); + + int createUniqueFamilyId () const; + std::string createUniqueFamilyName (const char* baseName) const; + + void load_0000 (Iff& iff); + +private: + + FractalGroup (const FractalGroup& rhs); + FractalGroup& operator= (const FractalGroup& rhs); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.cpp new file mode 100644 index 00000000..9075fa4a --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.cpp @@ -0,0 +1,488 @@ +//=================================================================== +// +// HeightData.cpp +// asommers 2001-08-02 +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/HeightData.h" + +#include "sharedFile/Iff.h" +#include "sharedFoundation/PointerDeleter.h" +#include "sharedFoundation/VoidMemberFunction.h" +#include "sharedMath/Vector.h" +#include "sharedMath/Vector2d.h" + +#include +#include + +//=================================================================== + +static const Tag TAG_ROAD = TAG (R,O,A,D); +static const Tag TAG_SGMT = TAG (S,G,M,T); +static const Tag TAG_HDTA = TAG (H,D,T,A); + +//=================================================================== + +class HeightData::Segment +{ +public: + + Segment (); + ~Segment (); + + int getNumberOfPoints () const; + const Vector& getPoint (int index) const; + void setPoint (int index, const Vector& point); + bool find (const Vector2d& point, float& result) const; + + void addPoint (const Vector& point); + void clear (); + + void load (Iff& iff); + void save (Iff& iff); + + void createRoadData (); + +private: + + Segment (const Segment&); //lint -esym (754, Segment::Segment) + Segment& operator= (const Segment&); //lint -esym (754, Segment::operator=) + +private: + + typedef std::vector PointList; + PointList m_pointList; +}; + +//------------------------------------------------------------------- + +HeightData::Segment::Segment () : + m_pointList () +{ +} + +//------------------------------------------------------------------- + +HeightData::Segment::~Segment () +{ +} + +//------------------------------------------------------------------- + +int HeightData::Segment::getNumberOfPoints () const +{ + return static_cast (m_pointList.size ()); +} + +//------------------------------------------------------------------- + +const Vector& HeightData::Segment::getPoint (int index) const +{ + DEBUG_FATAL (index < 0 || index >= static_cast (m_pointList.size ()), ("index out of range %i <= %i < %i", 0, index, m_pointList.size ())); + return m_pointList [static_cast (index)]; +} + +//------------------------------------------------------------------- + +void HeightData::Segment::setPoint (int index, const Vector& point) +{ + DEBUG_FATAL (index < 0 || index >= static_cast (m_pointList.size ()), ("index out of range %i <= %i < %i", 0, index, m_pointList.size ())); + m_pointList [static_cast (index)] = point; +} + +//------------------------------------------------------------------- + +bool HeightData::Segment::find (const Vector2d& oposition, float& result) const +{ + Vector2d position = oposition; + +#if 1 + { + const float x0 = std::min (m_pointList.begin ()->x, m_pointList.back ().x); + const float z0 = std::min (m_pointList.begin ()->z, m_pointList.back ().z); + const float x1 = std::max (m_pointList.begin ()->x, m_pointList.back ().x); + const float z1 = std::max (m_pointList.begin ()->z, m_pointList.back ().z); +// DEBUG_FATAL (position.x < x0 || position.x > x1 || position.y < z0 || position.y > z1, ("position out of range")); + position.x = clamp (x0, position.x, x1); + position.y = clamp (z0, position.y, z1); + } +#endif + + const float width = m_pointList.back ().x - m_pointList.begin ()->x; + const float height = m_pointList.back ().z - m_pointList.begin ()->z; + + if (fabsf (width) >= fabsf (height)) + { + if (width >= 0) + { + DEBUG_FATAL (width == 0, ("this can't happen")); + + //-- go from -x to +x + PointList::const_iterator current = m_pointList.begin (); + PointList::const_iterator previous = current; + + for (; current != m_pointList.end () && current->x < position.x; previous = current, ++current) + ; + + DEBUG_FATAL (current == m_pointList.begin (), ("couldn't straddle begin")); + DEBUG_FATAL (current == m_pointList.end (), ("couldn't straddle end")); + + const float t = (position.x - previous->x) / (current->x - previous->x); + result = linearInterpolate (previous->y, current->y, t); + } + else + { + //-- go from +x to -x + PointList::const_reverse_iterator current = m_pointList.rbegin (); + PointList::const_reverse_iterator previous = current; + + for (; current != m_pointList.rend () && current->x < position.x; previous = current, ++current) + ; + + DEBUG_FATAL (current == m_pointList.rbegin (), ("couldn't straddle rbegin")); + DEBUG_FATAL (current == m_pointList.rend (), ("couldn't straddle rend")); + + const float t = (position.x - previous->x) / (current->x - previous->x); + result = linearInterpolate (previous->y, current->y, t); + } + } + else + { + if (height >= 0) + { + DEBUG_FATAL (height == 0, ("this can't happen")); + + //-- go from -z to +z + PointList::const_iterator current = m_pointList.begin (); + PointList::const_iterator previous = current; + + for (; current != m_pointList.end () && current->z < position.y; previous = current, ++current) + ; + + DEBUG_FATAL (current == m_pointList.begin (), ("couldn't straddle begin")); + DEBUG_FATAL (current == m_pointList.end (), ("couldn't straddle end")); + + const float t = (position.y - previous->z) / (current->z - previous->z); + result = linearInterpolate (previous->y, current->y, t); + } + else + { + //-- go from +z to -z + PointList::const_reverse_iterator current = m_pointList.rbegin (); + PointList::const_reverse_iterator previous = current; + + for (; current != m_pointList.rend () && current->z < position.y; previous = current, ++current) + ; + + DEBUG_FATAL (current == m_pointList.rbegin (), ("couldn't straddle rbegin")); + DEBUG_FATAL (current == m_pointList.rend (), ("couldn't straddle rend")); + + const float t = (position.y - previous->z) / (current->z - previous->z); + result = linearInterpolate (previous->y, current->y, t); + } + } + + return true; +} + +//------------------------------------------------------------------- + +void HeightData::Segment::addPoint (const Vector& point) +{ + m_pointList.push_back (point); +} + +//------------------------------------------------------------------- + +void HeightData::Segment::clear () +{ + m_pointList.clear (); +} + +//------------------------------------------------------------------- + +void HeightData::Segment::load (Iff& iff) +{ + iff.enterChunk (TAG_SGMT); + + const int n = iff.getChunkLengthLeft (static_cast (sizeof (Vector))); + int i; + for (i = 0; i < n; ++i) + m_pointList.push_back (iff.read_floatVector ()); + + iff.exitChunk (TAG_SGMT); +} + +//------------------------------------------------------------------- + +void HeightData::Segment::save (Iff& iff) +{ + iff.insertChunk (TAG_SGMT); + + uint i; + for (i = 0; i < m_pointList.size (); ++i) + iff.insertChunkFloatVector (m_pointList [i]); + + iff.exitChunk (TAG_SGMT); +} + +//------------------------------------------------------------------- + +void HeightData::Segment::createRoadData () +{ + //-- road data is an averaged original data + if (m_pointList.size () > 3) + { + std::vector newPointList; + newPointList.push_back (m_pointList [0]); + + unsigned int i; + for (i = 1; i < m_pointList.size () - 1; ++i) + { + const float y = (m_pointList [i - 1].y + m_pointList [i].y + m_pointList [i + 1].y) / 3.f; + + newPointList.push_back (Vector (m_pointList [i].x, y, m_pointList [i].z)); + } + + newPointList.push_back (m_pointList [i]); + + m_pointList.swap (newPointList); + } +} + +//=================================================================== + +HeightData::HeightData () : + m_segmentList (NON_NULL (new SegmentList)), + m_needsRecalculateExtents (true) +{ +} + +//------------------------------------------------------------------- + +HeightData::~HeightData () +{ + clear (); + delete m_segmentList; + m_segmentList = 0; +} + +//------------------------------------------------------------------- + +void HeightData::load (Iff& iff) +{ + if (! (iff.enterForm (TAG_ROAD, true) || iff.enterForm (TAG_HDTA, true))) + return; + + clear (); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + FATAL (true, ("invalid form")); + } + + iff.exitForm (); + + recalculateExtents (); +} + +//------------------------------------------------------------------- + +void HeightData::load_0000 (Iff& iff) +{ + addSegment (); + + iff.enterChunk (TAG_0000); + + const int n = iff.getChunkLengthLeft (static_cast (sizeof (Vector))); + int i; + for (i = 0; i < n; ++i) + addPoint (iff.read_floatVector ()); + + iff.exitChunk (TAG_0000); +} + +//------------------------------------------------------------------- + +void HeightData::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + int numberOfSegments = iff.getNumberOfBlocksLeft (); + while (numberOfSegments-- > 0) + { + addSegment (); + + m_segmentList->back ()->load (iff); + } + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void HeightData::save (Iff& iff) const +{ + iff.insertForm (TAG_HDTA); + + iff.insertForm (TAG_0001); + + uint i; + for (i = 0; i < m_segmentList->size (); ++i) + (*m_segmentList) [i]->save (iff); + + iff.exitForm (TAG_0001); + + iff.exitForm (TAG_HDTA); +} + +//------------------------------------------------------------------- + +void HeightData::clear () +{ + std::for_each (m_segmentList->begin (), m_segmentList->end (), PointerDeleter ()); + m_segmentList->clear (); +} + +//------------------------------------------------------------------- + +void HeightData::addSegment () +{ + m_segmentList->push_back (new Segment ()); +} + +//------------------------------------------------------------------- + +void HeightData::addPoint (const Vector& point) +{ + m_segmentList->back ()->addPoint (point); + + m_needsRecalculateExtents = true; +} + +//------------------------------------------------------------------- + +int HeightData::getNumberOfSegments () const +{ + return static_cast (m_segmentList->size ()); +} + +//------------------------------------------------------------------- + +int HeightData::getNumberOfPoints (int segmentIndex) const +{ + if (m_segmentList->size ()) + { + DEBUG_FATAL (segmentIndex < 0 || segmentIndex >= static_cast (m_segmentList->size ()), ("index out of range %i <= %i < %i", 0, segmentIndex, m_segmentList->size ())); + return (*m_segmentList) [static_cast (segmentIndex)]->getNumberOfPoints (); + } + + return 0; +} + +//------------------------------------------------------------------- + +const Vector& HeightData::getPoint (int segmentIndex, int pointIndex) const +{ + if (m_segmentList->size ()) + { + DEBUG_FATAL (segmentIndex < 0 || segmentIndex >= static_cast (m_segmentList->size ()), ("index out of range %i <= %i < %i", 0, segmentIndex, m_segmentList->size ())); + return (*m_segmentList) [static_cast (segmentIndex)]->getPoint (pointIndex); + } + + return Vector::zero; +} + +//------------------------------------------------------------------- + +bool HeightData::find (int segmentIndex, const Vector2d& position, float& result) const +{ + if (m_segmentList->size ()) + { + DEBUG_FATAL (segmentIndex < 0 || segmentIndex >= static_cast (m_segmentList->size ()), ("index out of range %i <= %i < %i", 0, segmentIndex, m_segmentList->size ())); + return (*m_segmentList) [static_cast (segmentIndex)]->find (position, result); + } + + return false; +} + +//------------------------------------------------------------------- + +void HeightData::recalculateExtents () +{ + m_needsRecalculateExtents = false; +} + +//------------------------------------------------------------------- + +void HeightData::createRoadData () +{ + uint i; + for (i = 1; i < m_segmentList->size (); ++i) + (*m_segmentList) [i]->setPoint (0, (*m_segmentList) [i - 1]->getPoint ((*m_segmentList) [i - 1]->getNumberOfPoints () - 1)); + + std::for_each (m_segmentList->begin (), m_segmentList->end (), VoidMemberFunction (&Segment::createRoadData)); +} + +//------------------------------------------------------------------- + +void HeightData::createRiverData () +{ + //-- river data is a downward-terraced original data + const float epsilon = sin (convertDegreesToRadians (5.f)) * 4.f; + + float minimum = FLT_MAX - epsilon; + + uint i; + for (i = 0; i < m_segmentList->size (); ++i) + { + Segment* const segment = (*m_segmentList) [i]; + + int j; + for (j = 0; j < segment->getNumberOfPoints (); ++j) + { + Vector point = segment->getPoint (j); + + if (j == 0) + { + if (i == 0) + minimum = point.y; + else + { + point.y = minimum; + segment->setPoint (j, point); + } + } + else + if (point.y >= minimum + epsilon) + { + minimum += epsilon; + point.y = minimum; + segment->setPoint (j, point); + } + else + if (point.y < minimum) + minimum = point.y; + else + { + point.y = minimum; + segment->setPoint (j, point); + } + } + } +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.h b/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.h new file mode 100644 index 00000000..c7b445d9 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/HeightData.h @@ -0,0 +1,71 @@ +//=================================================================== +// +// HeightData.h +// asommers 2001-08-02 +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_HeightData_H +#define INCLUDED_HeightData_H + +//=================================================================== + +class Iff; +class Vector; +class Vector2d; + +//=================================================================== + +class HeightData +{ +public: + + HeightData (); + ~HeightData (); + + void load (Iff& iff); + void save (Iff& iff) const; + + //-- creation + void clear (); + void addSegment (); + void addPoint (const Vector& point); + + //-- query + int getNumberOfSegments () const; + int getNumberOfPoints (int segmentIndex) const; + const Vector& getPoint (int segmentIndex, int pointIndex) const; + bool find (int segmentIndex, const Vector2d& position, float& result) const; + + //-- call one of these once all the points have been added + void createRoadData (); + void createRiverData (); + +private: + + void recalculateExtents (); + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + +private: + + HeightData (const HeightData&); + HeightData& operator= (const HeightData&); + +private: + + class Segment; + typedef stdvector::fwd SegmentList; + SegmentList* m_segmentList; + + bool m_needsRecalculateExtents; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.cpp new file mode 100644 index 00000000..7322773e --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.cpp @@ -0,0 +1,1208 @@ +// +// RadialGroup.cpp +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/RadialGroup.h" + +#include "sharedFile/Iff.h" + +// ====================================================================== +// RadialGroupNamespace +// ====================================================================== + +namespace RadialGroupNamespace +{ + RadialGroup::FamilyChildData const ms_defaultFamilyChildData; +} + +using namespace RadialGroupNamespace; + +//------------------------------------------------------------------- +// +// RadialGroup::Info +// +RadialGroup::Info::Info() : + m_familyId(0), + m_childChoice(0) +{ +} + +//------------------------------------------------------------------- + +RadialGroup::Info::~Info() +{ +} + +//------------------------------------------------------------------- + +int RadialGroup::Info::getFamilyId() const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void RadialGroup::Info::setFamilyId(int const familyId) +{ + m_familyId = static_cast(familyId); +} + +//------------------------------------------------------------------- + +float RadialGroup::Info::getChildChoice() const +{ + return static_cast(m_childChoice) / 255.f; +} + +//------------------------------------------------------------------- + +void RadialGroup::Info::setChildChoice(float childChoice) +{ + m_childChoice = static_cast(childChoice * 255.f); +} + +//------------------------------------------------------------------- +// +// RadialGroup::FamilyChildData +// +RadialGroup::FamilyChildData::FamilyChildData () : + familyId (0), + weight (0.f), + shaderTemplateName (0), + distance (0), + minWidth (0), + maxWidth (0), + minHeight (0), + maxHeight (0), + maintainAspectRatio(false), + period (0), + displacement (0), + shouldSway (false), + alignToTerrain (false), + createPlus (false) +{ +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData::~FamilyChildData () +{ + shaderTemplateName = 0; +} + +//------------------------------------------------------------------- +// +// RadialGroup::Family +// +class RadialGroup::Family +{ +private: + + int familyId; + char* name; + PackedRgb color; + + //-- family data + float density; + + //-- child list + mutable ArrayList childList; + +private: + + void removeChild (int childIndex); + +private: + + Family (); + Family (const Family& rhs); //lint -esym (754, Family::Family) + Family& operator= (const Family& rhs); //lint -esym (754, Family::operator=) + +public: + + explicit Family (int newFamilyId); + ~Family (); + + int getNumberOfChildren () const; + FamilyChildData const & getChild(int childIndex) const; + FamilyChildData const & getChild(char const * name) const; + + int createRadial (float randomNumber0To1) const; + + const char* getName () const; + void setName (const char* newName); + + const PackedRgb& getColor () const; + void setColor (const PackedRgb& newColor); + + float getDensity () const; + void setDensity (float newDensity); + + int getFamilyId () const; + void setFamilyId (int newId); + + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + void setChild (const FamilyChildData& familyChildData); + + void renameChild (const char* oldName, const char* newName); +}; + +//------------------------------------------------------------------- + +RadialGroup::Family::Family (int newFamilyId) : + familyId (newFamilyId), + name (0), + color (), + density (1), + childList () +{ +} + +//------------------------------------------------------------------- + +RadialGroup::Family::~Family () +{ + delete [] name; + name = 0; + + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + removeChild (i); + + childList.clear (); +} + +//------------------------------------------------------------------- + +int RadialGroup::Family::getNumberOfChildren () const +{ + return childList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::setFamilyId (int newFamilyId) +{ + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +const char* RadialGroup::Family::getName () const +{ + return name; +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::setName (const char* newName) +{ + if (name) + { + delete [] name; + name = 0; + } + + if (newName) + name = DuplicateString (newName); +} + +//------------------------------------------------------------------- + +const PackedRgb& RadialGroup::Family::getColor () const +{ + return color; +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::setColor (const PackedRgb& newColor) +{ + color = newColor; +} + +//------------------------------------------------------------------- + +int RadialGroup::Family::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- + +int RadialGroup::Family::createRadial (float randomNumber0To1) const +{ + DEBUG_FATAL ((randomNumber0To1 < 0.f || randomNumber0To1 > 1.f), ("Random number out of bounds: %g", randomNumber0To1)); + + float weightSum = 0.f; + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + weightSum += childList[i].weight; + + float randomNumber = randomNumber0To1 * weightSum; + + int radialIndex = 0; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (randomNumber <= childList[i].weight) + { + radialIndex = i; + break; + } + else + randomNumber -= childList[i].weight; + } + + return radialIndex; +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::addChild (const FamilyChildData& familyChildData) +{ + DEBUG_FATAL (familyId != familyChildData.familyId, ("adding child to wrong family")); + + //-- add the name, but not the shader or shader template. those will be loaded when the shader is actually used + FamilyChildData child = familyChildData; + child.familyId = familyId; + child.shaderTemplateName = DuplicateString (familyChildData.shaderTemplateName); + + childList.add (child); +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::removeChild (int childIndex) +{ + if (childList [childIndex].shaderTemplateName) + { + delete [] const_cast (childList [childIndex].shaderTemplateName); + childList [childIndex].shaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::removeChild (const FamilyChildData& familyChildData) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, familyChildData.shaderTemplateName) == 0) + break; + + DEBUG_FATAL (i >= childList.getNumberOfElements (), ("child not found")); + + //-- remove child from list + removeChild (i); + childList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::Family::getChild(int const childIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, childIndex, childList.size()); + return childList[childIndex]; +} + +//------------------------------------------------------------------- +// +// RadialGroup +// +RadialGroup::RadialGroup () : + familyList (), + errorFamilyColor (255, 0, 255) +{ +} + +//------------------------------------------------------------------- + +RadialGroup::~RadialGroup () +{ + //-- delete family list + removeAllFamilies (); +} + +//------------------------------------------------------------------- + +void RadialGroup::setFamilyId (int familyIndex, int newFamilyId) +{ + familyList [familyIndex]->setFamilyId (newFamilyId); +} + +//------------------------------------------------------------------- + +const RadialGroup::Info RadialGroup::getDefaultRadial () const +{ + Info rfgi; + rfgi.setFamilyId(0); + rfgi.setChildChoice(0.f); + + return rfgi; +} + +//------------------------------------------------------------------- + +int RadialGroup::findFamilyIndex (int familyId) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getFamilyId () == familyId) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +int RadialGroup::findFamilyIndex (const PackedRgb& desiredColor) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getColor () == desiredColor) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +void RadialGroup::removeAllFamilies () +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + { + delete familyList [i]; + familyList [i] = 0; + } + + familyList.clear (); +} + +//------------------------------------------------------------------- + +void RadialGroup::addFamily (int familyId, const char* name, const PackedRgb& color) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex != -1, ("family with id %i already exists", familyId)); + + if (familyIndex == -1) //lint !e774 //-- if always true + { + Family* family = new Family (familyId); + family->setColor (color); + family->setName (name); + familyList.add (family); + } //lint !e429 //-- family not freed or returned +} + +//------------------------------------------------------------------- + +void RadialGroup::removeFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + delete familyList [familyIndex]; + familyList [familyIndex] = 0; + + familyList.removeIndexAndCompactList (familyIndex); +} + +//------------------------------------------------------------------- + +void RadialGroup::addChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->addChild (familyData); +} + +//------------------------------------------------------------------- + +void RadialGroup::removeChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->removeChild (familyData); +} + +//------------------------------------------------------------------- + +int RadialGroup::getNumberOfFamilies () const +{ + return familyList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +int RadialGroup::getNumberOfChildren (int familyIndex) const +{ + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::getChild(int const familyIndex, int const childIndex) const +{ + VALIDATE_RANGE_INCLUSIVE_EXCLUSIVE(0, familyIndex, familyList.size()); + return familyList[familyIndex]->getChild(childIndex); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::createRadial(RadialGroup::Info const & rgi) const +{ + int const familyId = rgi.getFamilyId (); + float const childChoice = rgi.getChildChoice (); + DEBUG_FATAL (childChoice < 0.f || childChoice > 1.f, ("RadialGroup::createRadial: childChoice %1.2f out of bounds (0..1)", childChoice)); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + { + return familyList[familyIndex]->getChild(familyList[familyIndex]->createRadial(childChoice)); + } + + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("RadialGroup::chooseRadial - familyId %i not found, using default shader\n", familyId)); + return ms_defaultFamilyChildData; +} + +//------------------------------------------------------------------- + +const RadialGroup::Info RadialGroup::chooseRadial (int familyId) const +{ + Info rfgi = getDefaultRadial (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + rfgi.setFamilyId(familyId); + else + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("RadialGroup::chooseRadial - familyId %i not found, using default shader\n", familyId)); + + return rfgi; +} + +//------------------------------------------------------------------- + +const RadialGroup::Info RadialGroup::chooseRadial (const PackedRgb& desiredColor) const +{ + Info rfgi = getDefaultRadial (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + rfgi.setFamilyId(familyList[familyIndex]->getFamilyId()); + else + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("RadialGroup::chooseRadial - family with color %i %i %i not found, using default shader\n", desiredColor.r, desiredColor.g, desiredColor.b)); + + return rfgi; +} + +//------------------------------------------------------------------- + +void RadialGroup::load (Iff& iff) +{ + //-- delete family list first + removeAllFamilies (); + + //-- load data + if (iff.enterForm (TAG (R,G,R,P), true)) + { + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + + default: + DEBUG_FATAL (true, ("RadialGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void RadialGroup::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (R,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("RadialGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const float distance = iff.read_float (); + const float width = iff.read_float (); + const float height = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + fcd.distance = distance; + fcd.minWidth = width; + fcd.maxWidth = width; + fcd.minHeight = height; + fcd.maxHeight = height; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void RadialGroup::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (R,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("RadialGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const float distance = iff.read_float (); + const float width = iff.read_float (); + const float height = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + fcd.distance = distance; + fcd.minWidth = width; + fcd.maxWidth = width; + fcd.minHeight = height; + fcd.maxHeight = height; + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void RadialGroup::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (R,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("RadialGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const float distance = iff.read_float (); + const float width = iff.read_float (); + const float height = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + fcd.distance = distance; + fcd.minWidth = width; + fcd.maxWidth = width; + fcd.minHeight = height; + fcd.maxHeight = height; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void RadialGroup::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (R,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("RadialGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + const float weight = iff.read_float (); + const float distance = iff.read_float (); + const float width = iff.read_float (); + const float height = iff.read_float (); + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + const bool alignToTerrain = iff.read_int32 () != 0; + const bool createPlus = iff.read_int32 () != 0; + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + fcd.distance = distance; + fcd.minWidth = width; + fcd.maxWidth = width; + fcd.minHeight = height; + fcd.maxHeight = height; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + fcd.alignToTerrain = alignToTerrain; + fcd.createPlus = createPlus; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +void RadialGroup::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (R,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("RadialGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setDensity (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + + const float weight = iff.read_float (); + const float distance = iff.read_float (); + const float minWidth = iff.read_float (); + const float maxWidth = iff.read_float (); + const float minHeight = iff.read_float (); + const float maxHeight = iff.read_float (); + const bool maintainAspectRatio = iff.read_int32 () != 0; + const bool shouldSway = iff.read_int32 () != 0; + const float displacement = iff.read_float (); + const float period = iff.read_float (); + const bool alignToTerrain = iff.read_int32 () != 0; + const bool createPlus = iff.read_int32 () != 0; + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + fcd.distance = distance; + + + fcd.minWidth = minWidth; + fcd.maxWidth = maxWidth; + fcd.minHeight = minHeight; + fcd.maxHeight = maxHeight; + fcd.shouldSway = shouldSway; + fcd.displacement = displacement; + fcd.period = period; + fcd.alignToTerrain = alignToTerrain; + fcd.createPlus = createPlus; + fcd.maintainAspectRatio = maintainAspectRatio; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void RadialGroup::save (Iff& iff) const +{ + iff.insertForm (TAG (R,G,R,P)); + + iff.insertForm (TAG_0004); + + int numberOfFamilies = getNumberOfFamilies (); + int i; + for (i = 0; i < numberOfFamilies; i++) + { + const Family* family = familyList [i]; + + iff.insertChunk (TAG (R,F,A,M)); + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + iff.insertChunkData (static_cast (family->getColor ().r)); + iff.insertChunkData (static_cast (family->getColor ().g)); + iff.insertChunkData (static_cast (family->getColor ().b)); + iff.insertChunkData (family->getDensity ()); + + int numberOfChildren = getNumberOfChildren (i); + iff.insertChunkData (numberOfChildren); + + int j; + for (j = 0; j < numberOfChildren; j++) + { + const FamilyChildData &fcd = getChild (i, j); + + iff.insertChunkString (fcd.shaderTemplateName); + iff.insertChunkData (fcd.weight); + iff.insertChunkData (fcd.distance); + iff.insertChunkData (fcd.minWidth); + iff.insertChunkData (fcd.maxWidth); + iff.insertChunkData (fcd.minHeight); + iff.insertChunkData (fcd.maxHeight); + iff.insertChunkData (fcd.maintainAspectRatio ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.shouldSway ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.displacement); + iff.insertChunkData (fcd.period); + iff.insertChunkData (fcd.alignToTerrain ? static_cast (1) : static_cast (0)); + iff.insertChunkData (fcd.createPlus ? static_cast (1) : static_cast (0)); + } + + iff.exitChunk (TAG (R,F,A,M)); + } + + iff.exitForm (TAG_0004); + + iff.exitForm (TAG (R,G,R,P)); +} + +//------------------------------------------------------------------- + +const PackedRgb& RadialGroup::getFamilyColor (int familyId) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + return familyList [familyIndex]->getColor (); + + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("RadialGroup::getFamilyColorById - familyId %i not found, using error color.\n", familyId)); + return errorFamilyColor; +} + +//------------------------------------------------------------------- + +int RadialGroup::getFamilyId (const PackedRgb& desiredColor) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + return familyList [familyIndex]->getFamilyId (); + + //-- color wasn't found, so log and return default shader + return 0; +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::renameChild (const char* oldName, const char* newName) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, oldName) == 0) + { + delete [] const_cast (childList [i].shaderTemplateName); + childList [i].shaderTemplateName = DuplicateString (newName); + } +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::setChild (const FamilyChildData& familyChildData) +{ + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (strcmp (familyChildData.shaderTemplateName, childList [i].shaderTemplateName) == 0) + { + const char* shaderTemplateName = childList [i].shaderTemplateName; + + childList [i] = familyChildData; + childList [i].shaderTemplateName = shaderTemplateName; + + return; + } + } + + DEBUG_FATAL (true, ("child %s not found in family", familyChildData.shaderTemplateName)); +} + +//------------------------------------------------------------------- + +void RadialGroup::renameChild (int familyId, const char* oldName, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->renameChild (oldName, newName); +} + + +//------------------------------------------------------------------- + +int RadialGroup::getFamilyNumberOfChildren (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +const char* RadialGroup::getFamilyName (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getName (); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::getFamilyChild(int familyId, int childIndex) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return getChild (familyIndex, childIndex); +} + +//------------------------------------------------------------------- + +void RadialGroup::setFamilyChild (int familyId, const FamilyChildData& familyChildData) +{ + const int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setChild (familyChildData); +} + +//------------------------------------------------------------------- + +void RadialGroup::setFamilyName (int familyId, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setName (newName); +} + +//------------------------------------------------------------------- + +void RadialGroup::setFamilyColor (int familyId, const PackedRgb& newColor) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setColor (newColor); +} + +//------------------------------------------------------------------- + +int RadialGroup::getFamilyId (int familyIndex) const +{ + return familyList [familyIndex]->getFamilyId (); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::getFamilyChild(int familyId, char const * childName) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getChild (childName); +} + +//------------------------------------------------------------------- + +RadialGroup::FamilyChildData const & RadialGroup::Family::getChild(char const * const childName) const +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, childName) == 0) + return getChild (i); + + DEBUG_FATAL (true, ("child %s not found", childName)); + return ms_defaultFamilyChildData; +} + +//------------------------------------------------------------------- + +bool RadialGroup::hasFamily (int familyId) const +{ + return findFamilyIndex (familyId) != -1; +} + +//------------------------------------------------------------------- + +bool RadialGroup::hasFamily (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return true; + + return false; +} + +//------------------------------------------------------------------- + +int RadialGroup::getFamilyId (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return familyList [i]->getFamilyId (); + + DEBUG_FATAL (true, ("family with name %s not found", name)); + + return -1; //lint !e527 //unreachable +} + +//------------------------------------------------------------------- + +float RadialGroup::Family::getDensity () const +{ + return density; +} + +//------------------------------------------------------------------- + +void RadialGroup::Family::setDensity (float newDensity) +{ + density = newDensity; +} + +//------------------------------------------------------------------- + +float RadialGroup::getFamilyDensity (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getDensity (); +} + +//------------------------------------------------------------------- + +void RadialGroup::setFamilyDensity (int familyId, float density) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setDensity (density); +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.h new file mode 100644 index 00000000..8597181c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/RadialGroup.h @@ -0,0 +1,154 @@ +//=================================================================== +// +// RadialGroup.h +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_RadialGroup_H +#define INCLUDED_RadialGroup_H + +//=================================================================== + +#include "sharedFoundation/ArrayList.h" +#include "sharedMath/PackedRgb.h" + +class Iff; + +//=================================================================== + +class RadialGroup +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Info holds info about a radial group and its child choice + // + struct Info + { + public: + + Info(); + ~Info(); + + int getFamilyId() const; + void setFamilyId(int familyId); + float getChildChoice() const; + void setChildChoice(float childChoice); + + private: + + uint8 m_familyId; + uint8 m_childChoice; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // FamilyChildData allows creation of RadialGroups + // + struct FamilyChildData + { + public: + + int familyId; + float weight; + const char* shaderTemplateName; + float distance; + float minWidth; + float maxWidth; + float minHeight; + float maxHeight; + bool maintainAspectRatio; + float period; + float displacement; + bool shouldSway; + bool alignToTerrain; + bool createPlus; + + public: + + FamilyChildData (); + ~FamilyChildData (); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + class Family; + +private: + + ArrayList familyList; + PackedRgb errorFamilyColor; + +private: + + int findFamilyIndex (int familyId) const; + int findFamilyIndex (const PackedRgb& desiredColor) const; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + +private: + + RadialGroup (const RadialGroup& rhs); + RadialGroup& operator= (const RadialGroup& rhs); + +public: + + RadialGroup (); + ~RadialGroup (); + + const Info getDefaultRadial () const; + const Info chooseRadial (int familyId) const; + const Info chooseRadial (const PackedRgb& desiredColor) const; + + FamilyChildData const & createRadial(RadialGroup::Info const & rfgi) const; + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void removeAllFamilies (); + + //-- family id routines + void addFamily (int familyId, const char* name, const PackedRgb& color); + void removeFamily (int familyId); + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + bool hasFamily (int familyId) const; + bool hasFamily (const char* name) const; + + int getFamilyId (const PackedRgb& desiredColor) const; + int getFamilyId (const char* name) const; + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + const PackedRgb& getFamilyColor (int familyId) const; + void setFamilyColor (int familyId, const PackedRgb& prgb); + int getFamilyNumberOfChildren (int familyId) const; + void renameChild (int familyId, const char* oldName, const char* newName); + FamilyChildData const & getFamilyChild(int familyId, char const * childName) const; + FamilyChildData const & getFamilyChild(int familyId, int childIndex) const; + void setFamilyChild (int familyId, const FamilyChildData& familyChildData); + float getFamilyDensity (int familyId) const; + void setFamilyDensity (int familyId, float density); + + //-- family index routines + int getNumberOfFamilies () const; + int getNumberOfChildren (int familyIndex) const; + FamilyChildData const & getChild(int familyIndex, int childIndex) const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.cpp new file mode 100644 index 00000000..b511c3a4 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.cpp @@ -0,0 +1,1473 @@ +// +// ShaderGroup.cpp +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/ShaderGroup.h" + +#include "sharedFile/Iff.h" +#include "sharedFile/TreeFile.h" +#include "sharedObject/ObjectTemplate.h" +#include "sharedObject/ObjectTemplateList.h" + +//------------------------------------------------------------------- +// +// ShaderGroup::Info +// +ShaderGroup::Info::Info () : + m_priority (0), + m_familyId (0), + m_childChoice (0) +{ +} + +//------------------------------------------------------------------- + +ShaderGroup::Info::~Info () +{ +} + +//------------------------------------------------------------------- + +int ShaderGroup::Info::getPriority () const +{ + return m_priority; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Info::setPriority (int const priority) +{ + m_priority = static_cast (priority); +} + +//------------------------------------------------------------------- + +int ShaderGroup::Info::getFamilyId () const +{ + return m_familyId; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Info::setFamilyId (int const familyId) +{ + m_familyId = static_cast (familyId); +} + +//------------------------------------------------------------------- + +float ShaderGroup::Info::getChildChoice () const +{ + return static_cast (m_childChoice) / 255.f; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Info::setChildChoice (float childChoice) +{ + m_childChoice = static_cast (childChoice * 255.f); +} + +//------------------------------------------------------------------- +// +// ShaderGroup::FamilyChildData +// +ShaderGroup::FamilyChildData::FamilyChildData () : + familyId (0), + shaderTemplateName (0), + weight (0.f) +{ +} + +//------------------------------------------------------------------- + +ShaderGroup::FamilyChildData::~FamilyChildData () +{ + shaderTemplateName = 0; +} + +//------------------------------------------------------------------- +// +// ShaderGroup::Family +// +class ShaderGroup::Family +{ +private: + + int familyId; + char* name; + PackedRgb color; + + //-- family data + float m_featherClamp; + float shaderSize; + char* surfacePropertiesName; + const ObjectTemplate* surfaceProperties; + + //-- child data + mutable ArrayList childList; + +private: + + void removeChild (int childIndex); + +private: + + Family (); + Family (const Family& rhs); //lint -esym(754, Family::Family) + Family& operator= (const Family& rhs); //lint -esym(754, Family::operator=) + +public: + + explicit Family (int newFamilyId); + ~Family (); + + int getNumberOfChildren () const; + const FamilyChildData getChild (int childIndex) const; + const FamilyChildData getChild (const char* name) const; + void setChild (const FamilyChildData& familyChildData); + + int createShader (float randomNumber0To1) const; + + const char* getName () const; + void setName (const char* newName); + + const PackedRgb& getColor () const; + void setColor (const PackedRgb& newColor); + + float getFeatherClamp () const; + void setFeatherClamp (float featherClamp); + + float getShaderSize () const; + void setShaderSize (float meters); + + const char* getSurfacePropertiesName () const; + void setSurfacePropertiesName (const char* familySurfacePropertiesName); + void loadSurfaceProperties (); + const ObjectTemplate* getSurfaceProperties () const; + + int getFamilyId () const; + void setFamilyId (int newId); + + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + + void renameChild (const char* oldName, const char* newName); + float getChildWeight (const char* childName); + void setChildWeight (const char* childName, float w); +}; + +//------------------------------------------------------------------- + +ShaderGroup::Family::Family (int newFamilyId) : + familyId (newFamilyId), + name (0), + color (), + m_featherClamp (1.f), + shaderSize (2.0f), + surfacePropertiesName (0), + surfaceProperties (0), + childList () +{ +} + +//------------------------------------------------------------------- + +ShaderGroup::Family::~Family () +{ + delete [] name; + name = 0; + + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + removeChild (i); + + childList.clear (); + + if (surfaceProperties) + { + const_cast (surfaceProperties)->releaseReference (); + surfaceProperties = 0; + } + + delete [] surfacePropertiesName; + surfacePropertiesName = 0; +} + +//------------------------------------------------------------------- + +int ShaderGroup::Family::getNumberOfChildren () const +{ + return childList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setFamilyId (int newFamilyId) +{ + DEBUG_FATAL (familyId < 0 || familyId > 255, ("ShaderGroup::Family::setFamilyId [%s]: familyId %i outside the legal range of 0..255", getName (), familyId)); + familyId = newFamilyId; +} + +//------------------------------------------------------------------- + +const ShaderGroup::FamilyChildData ShaderGroup::Family::getChild (int childIndex) const +{ + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = childList [childIndex].shaderTemplateName; + fcd.weight = childList [childIndex].weight; + + return fcd; +} + +//------------------------------------------------------------------- + +const char* ShaderGroup::Family::getName () const +{ + return name; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setName (const char* newName) +{ + if (name) + { + delete [] name; + name = 0; + } + + if (newName) + name = DuplicateString (newName); +} + +//------------------------------------------------------------------- + +const char* ShaderGroup::Family::getSurfacePropertiesName () const +{ + return surfacePropertiesName; +} + +//------------------------------------------------------------------- + +const ObjectTemplate* ShaderGroup::Family::getSurfaceProperties () const +{ + return surfaceProperties; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setSurfacePropertiesName (const char* newSurfacePropertiesName) +{ + if (surfacePropertiesName) + { + delete [] surfacePropertiesName; + surfacePropertiesName = 0; + } + + if (newSurfacePropertiesName) + surfacePropertiesName = DuplicateString (newSurfacePropertiesName); +} + +//------------------------------------------------------------------- + +const PackedRgb& ShaderGroup::Family::getColor () const +{ + return color; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setColor (const PackedRgb& newColor) +{ + color = newColor; +} + +//------------------------------------------------------------------- + +float ShaderGroup::Family::getShaderSize () const +{ + return shaderSize; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setShaderSize (float meters) +{ + shaderSize = meters; +} + +//------------------------------------------------------------------- + +int ShaderGroup::Family::getFamilyId () const +{ + return familyId; +} + +//------------------------------------------------------------------- + +int ShaderGroup::Family::createShader (float randomNumber0To1) const +{ + DEBUG_FATAL (randomNumber0To1 < 0.f || randomNumber0To1 > 1.f, ("Random number out of bounds: %g", randomNumber0To1)); + + float weightSum = 0.f; + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + weightSum += childList[i].weight; + + float randomNumber = randomNumber0To1 * weightSum; + + int shaderIndex = 0; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (randomNumber <= childList[i].weight) + { + shaderIndex = i; + break; + } + else + randomNumber -= childList[i].weight; + } + + return shaderIndex; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::addChild (const FamilyChildData& familyChildData) +{ + DEBUG_FATAL (familyId != familyChildData.familyId, ("adding child to wrong family")); + + //-- add the name, but not the shader or shader template. those will be loaded when the shader is actually used + FamilyChildData child = familyChildData; + child.shaderTemplateName = DuplicateString (familyChildData.shaderTemplateName); + + childList.add (child); +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::removeChild (int childIndex) +{ + if (childList [childIndex].shaderTemplateName) + { + delete [] const_cast (childList [childIndex].shaderTemplateName); + childList [childIndex].shaderTemplateName = 0; + } +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::removeChild (const FamilyChildData& familyChildData) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, familyChildData.shaderTemplateName) == 0) + break; + + DEBUG_FATAL (i >= childList.getNumberOfElements (), ("child not found")); + + //-- remove child from list + removeChild (i); + childList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +const ShaderGroup::FamilyChildData ShaderGroup::Family::getChild (const char* childName) const +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, childName) == 0) + return getChild (i); + + DEBUG_FATAL (true, ("child %s not found", childName)); + + FamilyChildData fcd; //lint !e527 //-- unreachable + return fcd; //lint !e527 //-- unreachable +} + +//------------------------------------------------------------------- +// +// ShaderGroup +// +ShaderGroup::ShaderGroup () : + familyList (), + errorFamilyColor (255, 0, 255) +{ +} + +//------------------------------------------------------------------- + +ShaderGroup::~ShaderGroup () +{ + //-- delete family list + removeAllFamilies (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyId (int familyIndex, int newFamilyId) +{ + familyList [familyIndex]->setFamilyId (newFamilyId); +} + +//------------------------------------------------------------------- + +const ShaderGroup::Info ShaderGroup::getDefaultShader () const +{ + return Info (); +} + +//------------------------------------------------------------------- + +int ShaderGroup::findFamilyIndex (int familyId) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getFamilyId () == familyId) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +int ShaderGroup::findFamilyIndex (const PackedRgb& desiredColor) const +{ + //-- no, so search list + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (familyList [i]->getColor () == desiredColor) + return i; + + //-- item still not found in list + return -1; +} + +//------------------------------------------------------------------- + +void ShaderGroup::removeAllFamilies () +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + { + delete familyList [i]; + familyList [i] = 0; + } + + familyList.clear (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::addFamily (int familyId, const char* name, const PackedRgb& color) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex != -1, ("family with id %i already exists", familyId)); + + if (familyIndex == -1) //lint !e774 //-- if always true + { + Family* family = new Family (familyId); + family->setColor (color); + family->setName (name); + familyList.add (family); + } //lint !e429 //-- family not freed or returned +} + +//------------------------------------------------------------------- + +void ShaderGroup::removeFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + delete familyList [familyIndex]; + familyList [familyIndex] = 0; + + familyList.removeIndexAndCompactList (familyIndex); +} + +//------------------------------------------------------------------- + +void ShaderGroup::addChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->addChild (familyData); +} + +//------------------------------------------------------------------- + +void ShaderGroup::removeChild (const FamilyChildData& familyData) +{ + int familyIndex = findFamilyIndex (familyData.familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyData.familyId)); + + familyList [familyIndex]->removeChild (familyData); +} + +//------------------------------------------------------------------- + +int ShaderGroup::getNumberOfFamilies () const +{ + return familyList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +int ShaderGroup::getNumberOfChildren (int familyIndex) const +{ + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +const ShaderGroup::FamilyChildData ShaderGroup::getChild (int familyIndex, int childIndex) const +{ + return familyList [familyIndex]->getChild (childIndex); +} + +//------------------------------------------------------------------- + +int ShaderGroup::createShader (const ShaderGroup::Info& sgi) const +{ + int const familyId = sgi.getFamilyId (); + float const childChoice = sgi.getChildChoice (); + DEBUG_FATAL (childChoice < 0.f || childChoice > 1.f, ("ShaderGroup::createShader: childChoice %1.2f out of bounds (0..1)", childChoice)); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + return familyList [familyIndex]->createShader (childChoice); + + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::chooseShader - familyId %i not found, using default shader\n", familyId)); + + return 0; +} + +//------------------------------------------------------------------- + +const ShaderGroup::Info ShaderGroup::chooseShader (int familyId) const +{ + Info sgi = getDefaultShader (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + { + sgi.setPriority (familyIndex); + sgi.setFamilyId (familyId); + } + else + { + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::chooseShader - familyId %i not found, using default shader\n", familyId)); + } + + return sgi; +} + +//------------------------------------------------------------------- + +const ShaderGroup::Info ShaderGroup::chooseShader (const PackedRgb& desiredColor) const +{ + Info sgi = getDefaultShader (); + + //-- search for the shader in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1 && familyList [familyIndex]->getNumberOfChildren () > 0) + { + sgi.setPriority (familyIndex); + sgi.setFamilyId (familyList [familyIndex]->getFamilyId ()); + } + else + { + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::chooseShader - family with color %i %i %i not found, using default shader\n", desiredColor.r, desiredColor.g, desiredColor.b)); + } + + return sgi; +} + +//------------------------------------------------------------------- + +void ShaderGroup::load (Iff& iff) +{ + //-- delete family list first + removeAllFamilies (); + + //-- load data + if (iff.enterForm (TAG (S,G,R,P), true)) + { + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + case TAG_0002: + load_0002 (iff); + break; + + case TAG_0003: + load_0003 (iff); + break; + + case TAG_0004: + load_0004 (iff); + break; + + case TAG_0005: + load_0005 (iff); + break; + + case TAG_0006: + load_0006 (iff); + break; + + default: + DEBUG_FATAL (true, ("ShaderGroup::load unknown tag")); + } + + iff.exitForm (); + } +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + family->setName ("null"); + + PackedRgb color; + color.r = 255; + color.g = 255; + color.b = 255; + family->setColor (color); + + family->setShaderSize (2.f); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + char nameBuffer [100]; + iff.read_string (nameBuffer, 100); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = 1.0f / static_cast(numberOfChildren); + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + + family->setShaderSize (2.f); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0002 (Iff& iff) +{ + iff.enterForm (TAG_0002); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + family->setShaderSize (static_cast (iff.read_float ())); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0003 (Iff& iff) +{ + iff.enterForm (TAG_0003); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + family->setShaderSize (iff.read_float ()); + + const float unused = iff.read_float (); + UNREF (unused); + + int numberOfChildren = iff.read_int32 (); +// DEBUG_FATAL (numberOfChildren <= 0, ("family %i (id %i) has 0 children", i, familyId)); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0004 (Iff& iff) +{ + iff.enterForm (TAG_0004); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + family->setShaderSize (iff.read_float ()); + family->setFeatherClamp (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0005 (Iff& iff) +{ + iff.enterForm (TAG_0005); + + char nameBuffer [100]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 100); + family->setName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + family->setShaderSize (iff.read_float ()); + family->setFeatherClamp (iff.read_float ()); + IGNORE_RETURN (iff.read_int32 ()); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 100); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::load_0006 (Iff& iff) +{ + iff.enterForm (TAG_0006); + + char nameBuffer [1000]; + + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterChunk (TAG (S,F,A,M)); + + int familyId = iff.read_int32 (); + + //-- see if family id is already in use + DEBUG_FATAL (findFamilyIndex (familyId) != -1, ("ShaderGroup::load familyId %i is already in use", familyId)); + + //-- add family + Family* family = new Family (familyId); + + iff.read_string (nameBuffer, 1000); + family->setName (nameBuffer); + + iff.read_string (nameBuffer, 1000); + family->setSurfacePropertiesName (nameBuffer); + + PackedRgb color; + color.r = iff.read_uint8 (); + color.g = iff.read_uint8 (); + color.b = iff.read_uint8 (); + family->setColor (color); + family->setShaderSize (iff.read_float ()); + family->setFeatherClamp (iff.read_float ()); + + int numberOfChildren = iff.read_int32 (); + + int k; + for (k = 0; k < numberOfChildren; k++) + { + iff.read_string (nameBuffer, 1000); + + float weight = iff.read_float (); + + FamilyChildData fcd; + fcd.familyId = familyId; + fcd.shaderTemplateName = nameBuffer; + fcd.weight = weight; + + family->addChild (fcd); + } + + familyList.add (family); + + iff.exitChunk (); + } //lint !e429 //-- family not freed or returned + + iff.exitForm (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::save (Iff& iff) const +{ + iff.insertForm (TAG (S,G,R,P)); + + iff.insertForm (TAG_0006); + + int numberOfFamilies = getNumberOfFamilies (); + int i; + for (i = 0; i < numberOfFamilies; i++) + { + const Family* family = familyList [i]; + + iff.insertChunk (TAG (S,F,A,M)); + iff.insertChunkData (static_cast (family->getFamilyId ())); + iff.insertChunkString (family->getName ()); + iff.insertChunkString (family->getSurfacePropertiesName () ? family->getSurfacePropertiesName () : ""); + iff.insertChunkData (static_cast (family->getColor ().r)); + iff.insertChunkData (static_cast (family->getColor ().g)); + iff.insertChunkData (static_cast (family->getColor ().b)); + iff.insertChunkData (family->getShaderSize ()); + iff.insertChunkData (family->getFeatherClamp ()); + + int numberOfChildren = getNumberOfChildren (i); + iff.insertChunkData (numberOfChildren); + + int j; + for (j = 0; j < numberOfChildren; j++) + { + const FamilyChildData fcd = getChild (i, j); + + iff.insertChunkString (fcd.shaderTemplateName); + iff.insertChunkData (fcd.weight); + } + + iff.exitChunk (TAG (S,F,A,M)); + } + + iff.exitForm (TAG_0006); + + iff.exitForm (TAG (S,G,R,P)); +} + +//------------------------------------------------------------------- + +const PackedRgb& ShaderGroup::getFamilyColor (int familyId) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + return familyList [familyIndex]->getColor (); + + //-- family id wasn't found, so log and return default shader + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::getFamilyColorById - familyId %i not found, using error color.\n", familyId)); + return errorFamilyColor; +} + +//------------------------------------------------------------------- + +float ShaderGroup::getFamilyShaderSize (int familyId) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + return familyList [familyIndex]->getShaderSize (); + + //-- family id wasn't found, so log and return default size + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::getFamilyShaderSize - familyId %i not found, using default size.\n", familyId)); + return 2.f; +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyShaderSize (int familyId, float meters) +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (familyId); + if (familyIndex != -1) + familyList [familyIndex]->setShaderSize (meters); + else + //-- family id wasn't found + DEBUG_REPORT_LOG_PRINT (true, ("ShaderGroup::setFamilyShaderSize - familyId %i not found.\n", familyId)); +} + +//------------------------------------------------------------------- + +int ShaderGroup::getFamilyId (const PackedRgb& desiredColor) const +{ + //-- search for the appearance in the family list + int familyIndex = findFamilyIndex (desiredColor); + if (familyIndex != -1) + return familyList [familyIndex]->getFamilyId (); + + //-- color wasn't found, so log and return default shader + return 0; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::renameChild (const char* oldName, const char* newName) +{ + //-- search for child + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, oldName) == 0) + { + delete [] const_cast (childList [i].shaderTemplateName); + childList [i].shaderTemplateName = DuplicateString (newName); + } +} + +//------------------------------------------------------------------- + +float ShaderGroup::Family::getChildWeight (const char* childName) +{ + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + if (_stricmp (childList [i].shaderTemplateName, childName) == 0) + return childList [i].weight; + + FATAL (true, ("Child %s not found", childName)); + + return 0.f; //lint !e527 //-- if always true +} + +//------------------------------------------------------------------ + +void ShaderGroup::Family::setChildWeight (const char* childName, float w) +{ + bool found = false; + for (int i = 0; i < childList.getNumberOfElements () && !found; i++) + if (_stricmp (childList [i].shaderTemplateName, childName) == 0) + { + childList [i].weight = w; + found = true; + } + + FATAL (!found, ("Child %s not found", childName)); +} + +//------------------------------------------------------------------- + +void ShaderGroup::renameChild (int familyId, const char* oldName, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->renameChild (oldName, newName); +} + + +//------------------------------------------------------------------- + +void ShaderGroup::promoteFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + if (familyIndex>0) + { + Family* tempFamily = familyList[familyIndex-1]; + familyList[familyIndex-1] = familyList[familyIndex]; + familyList[familyIndex] = tempFamily; + } + +} + +//------------------------------------------------------------------- + +void ShaderGroup::demoteFamily (int familyId) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + if (familyIndex < familyList.getNumberOfElements ()-1) + { + Family* tempFamily = familyList[familyIndex+1]; + familyList[familyIndex+1] = familyList[familyIndex]; + familyList[familyIndex] = tempFamily; + } +} + +//------------------------------------------------------------------- + +int ShaderGroup::getFamilyNumberOfChildren (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getNumberOfChildren (); +} + +//------------------------------------------------------------------- + +const char* ShaderGroup::getFamilyName (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getName (); +} + +//------------------------------------------------------------------- + +const ShaderGroup::FamilyChildData ShaderGroup::getFamilyChild (int familyId, int childIndex) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return getChild (familyIndex, childIndex); +} + + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyName (int familyId, const char* newName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setName (newName); +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyColor (int familyId, const PackedRgb& newColor) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setColor (newColor); +} + +//------------------------------------------------------------------- + +int ShaderGroup::getFamilyId (int familyIndex) const +{ + return familyList [familyIndex]->getFamilyId (); +} + +//------------------------------------------------------------------- + +bool ShaderGroup::hasFamily (int familyId) const +{ + return findFamilyIndex (familyId) != -1; +} + +//------------------------------------------------------------------- + +bool ShaderGroup::hasFamily (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return true; + + return false; +} + +//------------------------------------------------------------------- + +int ShaderGroup::getFamilyId (const char* name) const +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); i++) + if (_stricmp (name, familyList [i]->getName ()) == 0) + return familyList [i]->getFamilyId (); + + DEBUG_FATAL (true, ("family with name %s not found", name)); + + return -1; //lint !e527 //unreachable +} + +//------------------------------------------------------------------- + +float ShaderGroup::Family::getFeatherClamp () const +{ + return m_featherClamp; +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setFeatherClamp (float featherClamp) +{ + m_featherClamp = featherClamp; +} + +//------------------------------------------------------------------- + +float ShaderGroup::getFamilyFeatherClamp (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getFeatherClamp (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyFeatherClamp (int familyId, float featherClamp) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setFeatherClamp (featherClamp); +} + +//------------------------------------------------------------------- + +const char* ShaderGroup::getFamilySurfacePropertiesName (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getSurfacePropertiesName (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilySurfacePropertiesName (int familyId, const char* surfacePropertiesName) +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setSurfacePropertiesName (surfacePropertiesName); +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::setChild (const FamilyChildData& familyChildData) +{ + int i; + for (i = 0; i < childList.getNumberOfElements (); i++) + { + if (strcmp (familyChildData.shaderTemplateName, childList [i].shaderTemplateName) == 0) + { + const char* shaderTemplateName = childList [i].shaderTemplateName; + + childList [i] = familyChildData; + childList [i].shaderTemplateName = shaderTemplateName; + + return; + } + } + + DEBUG_FATAL (true, ("child %s not found in family", familyChildData.shaderTemplateName)); +} + +//------------------------------------------------------------------- + +const ShaderGroup::FamilyChildData ShaderGroup::getFamilyChild (int familyId, const char* childName) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getChild (childName); +} + +//------------------------------------------------------------------- + +void ShaderGroup::setFamilyChild (int familyId, const FamilyChildData& familyChildData) +{ + const int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + familyList [familyIndex]->setChild (familyChildData); +} + +//------------------------------------------------------------------- + +const ObjectTemplate* ShaderGroup::getFamilySurfaceProperties (int familyId) const +{ + int familyIndex = findFamilyIndex (familyId); + DEBUG_FATAL (familyIndex == -1, ("family with id %i not found", familyId)); + + return familyList [familyIndex]->getSurfaceProperties (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::loadSurfaceProperties () +{ + int i; + for (i = 0; i < familyList.getNumberOfElements (); ++i) + familyList [i]->loadSurfaceProperties (); +} + +//------------------------------------------------------------------- + +void ShaderGroup::Family::loadSurfaceProperties () +{ + if (surfaceProperties) + const_cast (surfaceProperties)->releaseReference (); + + surfaceProperties = 0; + + if (surfacePropertiesName && *surfacePropertiesName) + { + if (TreeFile::exists (surfacePropertiesName)) + surfaceProperties = ObjectTemplateList::fetch (surfacePropertiesName); + else + DEBUG_WARNING (true, ("Shader family %s could not open properties file %s\n", name, surfacePropertiesName)); + } +} + +//------------------------------------------------------------------- + + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.h b/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.h new file mode 100644 index 00000000..38359cda --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/ShaderGroup.h @@ -0,0 +1,172 @@ +//=================================================================== +// +// ShaderGroup.h +// asommers 9-17-2000 +// +// copyright 2000, verant interactive +// +//-- +// +// A ShaderGroup contains lists of families of textures organized by id. +// A shader family is a list of valid shaders for a specified id. The shader +// family also stores the name of the shader, its shaderTemplate, and +// the actual shader. The shader group will return const shaders for use +// with the terrain system. In the event that requested shader does not +// exist, the shader group will return a [clearly visible] default shader. +// Families will only create shaders when they are chosen. +// +//=================================================================== + +#ifndef SHADERGROUP_H +#define SHADERGROUP_H + +//=================================================================== + +#include "sharedFoundation/ArrayList.h" +#include "sharedMath/PackedRgb.h" + +class Iff; +class ObjectTemplate; + +//=================================================================== + +class ShaderGroup +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Info holds info about a shader and its priority + // + struct Info + { + public: + + Info (); + ~Info (); + + int getPriority () const; + void setPriority (int priority); + int getFamilyId () const; + void setFamilyId (int familyId); + float getChildChoice () const; + void setChildChoice (float childChoice); + + private: + + uint8 m_priority; + uint8 m_familyId; + uint8 m_childChoice; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // FamilyChildData allows creation of ShaderGroups + // + struct FamilyChildData + { + public: + + int familyId; + const char* shaderTemplateName; + float weight; + + public: + + FamilyChildData (); + ~FamilyChildData (); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + class Family; + +private: + + //-- list of families + ArrayList familyList; + + //-- + PackedRgb errorFamilyColor; + +private: + + int findFamilyIndex (int familyId) const; + int findFamilyIndex (const PackedRgb& desiredColor) const; + +private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + void load_0002 (Iff& iff); + void load_0003 (Iff& iff); + void load_0004 (Iff& iff); + void load_0005 (Iff& iff); + void load_0006 (Iff& iff); + +private: + + ShaderGroup (const ShaderGroup& rhs); + ShaderGroup& operator= (const ShaderGroup& rhs); + +public: + + ShaderGroup (); + ~ShaderGroup (); + + const Info getDefaultShader () const; + const Info chooseShader (int familyId) const; + const Info chooseShader (const PackedRgb& desiredColor) const; + + int createShader (const ShaderGroup::Info& sgi) const; + + //-- creation routines (for editor) + void load (Iff& iff); + void save (Iff& iff) const; + void removeAllFamilies (); + void loadSurfaceProperties (); + + //-- family id routines + void addFamily (int familyId, const char* name, const PackedRgb& color); + void removeFamily (int familyId); + void addChild (const FamilyChildData& familyChildData); + void removeChild (const FamilyChildData& familyChildData); + bool hasFamily (int familyId) const; + bool hasFamily (const char* name) const; + + int getFamilyId (const PackedRgb& desiredColor) const; + int getFamilyId (const char* name) const; + const char* getFamilyName (int familyId) const; + void setFamilyName (int familyId, const char* name); + const PackedRgb& getFamilyColor (int familyId) const; + void setFamilyColor (int familyId, const PackedRgb& prgb); + float getFamilyShaderSize (int familyId) const; + void setFamilyShaderSize (int familyId, float meters); + int getFamilyNumberOfChildren (int familyId) const; + void renameChild (int familyId, const char* oldName, const char* newName); + void promoteFamily (int familyId); + void demoteFamily (int familyId); + void promoteChild (int familyId, const char* childName); + void demoteChild (int familyId, const char* childName); + const FamilyChildData getFamilyChild (int familyId, const char* childName) const; + const FamilyChildData getFamilyChild (int familyId, int childIndex) const; + void setFamilyChild (int familyId, const FamilyChildData& familyChildData); + float getFamilyFeatherClamp (int familyId) const; + void setFamilyFeatherClamp (int familyId, float featherClamp); + const char* getFamilySurfacePropertiesName (int familyId) const; + void setFamilySurfacePropertiesName (int familyId, const char* familySurfacePropertiesName); + const ObjectTemplate* getFamilySurfaceProperties (int familyId) const; + + //-- family index routines + int getNumberOfFamilies () const; + int getNumberOfChildren (int familyIndex) const; + const FamilyChildData getChild (int familyIndex, int childIndex) const; + int getFamilyId (int familyIndex) const; + void setFamilyId (int familyIndex, int newId); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.cpp new file mode 100644 index 00000000..d1c6d645 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.cpp @@ -0,0 +1,2381 @@ +// +// TerrainGenerator.cpp +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainGenerator.h" + +#include "sharedDebug/PerformanceTimer.h" +#include "sharedFile/Iff.h" +#include "sharedMath/Vector2d.h" +#include "sharedTerrain/Feather.h" +#include "sharedTerrain/TerrainGeneratorLoader.h" +#include "sharedTerrain/Filter.h" + +#include +#include + +#if defined(PLATFORM_LINUX) +#include +#define _alloca alloca +#endif + +//=================================================================== +// TerrainGeneratorNamespace +//=================================================================== + +namespace TerrainGeneratorNamespace +{ + //------------------------------------------------------------------- + + // FuzzyOr (1, x) = 1 + template + inline const T FuzzyOr (const T& a, const T& b) + { + return std::max (a, b); + } + + //------------------------------------------------------------------- + + // FuzzyAnd (0, x) = 0 + template + inline const T FuzzyAnd (const T& a, const T& b) + { + return std::min (a, b); + } + + //------------------------------------------------------------------- +} + +using namespace TerrainGeneratorNamespace; + +//=================================================================== +// STATIC PUBLIC TerrainGenerator +//=================================================================== + +//------------------------------------------------------------------- +// +// TerrainGenerator::CreateChunkBuffer +// + +TerrainGenerator::CreateChunkBuffer::CreateChunkBuffer () : + heightMap (), + colorMap (), + shaderMap (), + floraStaticCollidableMap (), + floraStaticNonCollidableMap (), + floraDynamicNearMap (), + floraDynamicFarMap (), + environmentMap (), + vertexPositionMap (), + vertexNormalMap (), + excludeMap (), + passableMap () +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::CreateChunkBuffer::~CreateChunkBuffer () +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::CreateChunkBuffer::allocate (const int poleCount) +{ + heightMap.allocate (poleCount, poleCount); + colorMap.allocate (poleCount, poleCount); + shaderMap.allocate (poleCount, poleCount); + floraStaticCollidableMap.allocate (poleCount, poleCount); + floraStaticNonCollidableMap.allocate (poleCount, poleCount); + floraDynamicNearMap.allocate (poleCount, poleCount); + floraDynamicFarMap.allocate (poleCount, poleCount); + environmentMap.allocate (poleCount, poleCount); + vertexPositionMap.allocate (poleCount, poleCount); + vertexNormalMap.allocate (poleCount, poleCount); + excludeMap.allocate (poleCount, poleCount); + passableMap.allocate (poleCount, poleCount); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::CreateChunkBuffer::validate () const +{ + DEBUG_FATAL (heightMap.isEmpty (), ("heightMap has not been allocated")); + DEBUG_FATAL (colorMap.isEmpty (), ("colorMap has not been allocated")); + DEBUG_FATAL (shaderMap.isEmpty (), ("shaderMap has not been allocated")); + DEBUG_FATAL (floraStaticCollidableMap.isEmpty (), ("floraStaticCollidableMap has not been allocated")); + DEBUG_FATAL (floraStaticNonCollidableMap.isEmpty (), ("floraStaticNonCollidableMap has not been allocated")); + DEBUG_FATAL (floraDynamicNearMap.isEmpty (), ("floraDynamicNearMap has not been allocated")); + DEBUG_FATAL (floraDynamicFarMap.isEmpty (), ("floraDynamicFarMap has not been allocated")); + DEBUG_FATAL (environmentMap.isEmpty (), ("environmentMap has not been allocated")); + DEBUG_FATAL (vertexPositionMap.isEmpty (), ("vertexPositionMap has not been allocated")); + DEBUG_FATAL (vertexNormalMap.isEmpty (), ("vertexNormalMap has not been allocated")); + DEBUG_FATAL (excludeMap.isEmpty (), ("excludeMap has not been allocated")); + DEBUG_FATAL (passableMap.isEmpty (), ("passableMap has not been allocated")); +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::LayerItem +// +TerrainGenerator::LayerItem::LayerItem (const Tag tag) : + m_tag (tag), + m_active (true), + m_pruned(false), + m_name (0) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::LayerItem::~LayerItem () +{ + delete [] m_name; + m_name = 0; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::setActive (const bool active) +{ + m_active = active; +} + +//=================================================================== + +void TerrainGenerator::LayerItem::setName (const char* const name) +{ + delete [] m_name; + m_name = 0; + + if (name) + m_name = DuplicateString (name); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::prepare () +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::load (Iff& iff) +{ + iff.enterForm (TAG_IHDR); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + case TAG_0001: + load_0001 (iff); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } + + iff.exitForm (TAG_IHDR); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + iff.enterChunk (TAG_DATA); + + setActive (iff.read_int32 () != 0); + + char nameBuffer [100]; + iff.read_string (nameBuffer, 100); + + setName (nameBuffer); + + PackedRgb toolColorNowUnused; + toolColorNowUnused.r = iff.read_uint8 (); + toolColorNowUnused.g = iff.read_uint8 (); + toolColorNowUnused.b = iff.read_uint8 (); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::load_0001 (Iff& iff) +{ + iff.enterForm (TAG_0001); + + iff.enterChunk (TAG_DATA); + + setActive (iff.read_int32 () != 0); + + char nameBuffer [100]; + iff.read_string (nameBuffer, 100); + + setName (nameBuffer); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::LayerItem::save (Iff& iff) const +{ + iff.insertForm (TAG_IHDR); + + iff.insertForm (TAG_0001); + + iff.insertChunk (TAG_DATA); + + iff.insertChunkData (isActive () ? static_cast (1) : static_cast (0)); + iff.insertChunkString (getName () ? getName () : ""); + + iff.exitChunk (TAG_DATA); + + iff.exitForm (TAG_0001); + + iff.exitForm (TAG_IHDR); +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::GeneratorChunkData +// +TerrainGenerator::GeneratorChunkData::GeneratorChunkData (bool legacyMode) : + originOffset(0), + numberOfPoles(0), + upperPad(0), + distanceBetweenPoles (0), + start (), + heightMap (0), + colorMap (0), + shaderMap (0), + floraStaticCollidableMap (0), + floraStaticNonCollidableMap (0), + floraDynamicNearMap (0), + floraDynamicFarMap (0), + environmentMap (0), + vertexPositionMap (0), + vertexNormalMap (0), + excludeMap (0), + passableMap (0), + shaderGroup (0), + floraGroup (0), + radialGroup (0), + environmentGroup (0), + fractalGroup (0), + bitmapGroup (0), + m_legacyRandomGenerator(legacyMode ? new RandomGenerator : (RandomGenerator *)0), + normalsDirtyIUO (false), + shadersDirtyIUO (false), + chunkExtentIUO () +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::GeneratorChunkData::~GeneratorChunkData () +{ + heightMap = 0; + colorMap = 0; + shaderMap = 0; + floraStaticCollidableMap = 0; + floraStaticNonCollidableMap = 0; + floraDynamicNearMap = 0; + floraDynamicFarMap = 0; + environmentMap = 0; + vertexPositionMap = 0; + vertexNormalMap = 0; + excludeMap = 0; + passableMap = 0; + shaderGroup = 0; + floraGroup = 0; + radialGroup = 0; + environmentGroup = 0; + fractalGroup = 0; + bitmapGroup = 0; + delete m_legacyRandomGenerator; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::GeneratorChunkData::validate () const +{ + DEBUG_FATAL (numberOfPoles == 0, ("TerrainGenerator::GeneratorChunkData::validate - numberOfPoles == 0")); + DEBUG_FATAL (distanceBetweenPoles == 0, ("TerrainGenerator::GeneratorChunkData::validate - distanceBetweenPoles == 0")); + NOT_NULL (heightMap); + NOT_NULL (colorMap); + NOT_NULL (shaderMap); + NOT_NULL (floraStaticCollidableMap); + NOT_NULL (floraStaticNonCollidableMap); + NOT_NULL (floraDynamicNearMap); + NOT_NULL (floraDynamicFarMap); + NOT_NULL (environmentMap); + NOT_NULL (vertexPositionMap); + NOT_NULL (vertexNormalMap); + NOT_NULL (excludeMap); + NOT_NULL (passableMap); + NOT_NULL (shaderGroup); + NOT_NULL (floraGroup); + NOT_NULL (radialGroup); + NOT_NULL (environmentGroup); + NOT_NULL (fractalGroup); + NOT_NULL (bitmapGroup); +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::Boundary +// +TerrainGenerator::Boundary::Boundary (const Tag tag, const TerrainGeneratorBoundaryType type) : + TerrainGenerator::LayerItem (tag), + m_type (type), + m_featherFunction (TGFF_linear), + m_featherDistance (0.f) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::Boundary::~Boundary () +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::rotate (const float /*angle*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::rotate (const float /*angle*/, const Vector2d& /*center*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::translate (const Vector2d& /*translation*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::scale (const float /*scalar*/) +{ +} + +//------------------------------------------------------------------- + +const Vector2d TerrainGenerator::Boundary::getCenter () const +{ + return Vector2d (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::setCenter (const Vector2d& /*center*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::setRotation (const float /*angle*/) +{ +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const +{ + if (!intersects(scanArea)) + { + return; + } + + const int sampleWidth = numberOfPoles-1; + if (sampleWidth==0) + { + float amount = isWithin(scanArea.x0, scanArea.y0); + const Feather feather(getFeatherFunction()); + o_data[0]=std::max(o_data[0], feather.feather(0.f, 1.f, amount)); + return; + } + + const float scale = (scanArea.x1 - scanArea.x0) / float(sampleWidth); + for (int z=0;zdestRow[x]) + { + destRow[x]=amount; + } + } + } +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::Filter +// +TerrainGenerator::Filter::Filter (const Tag tag, const TerrainGeneratorFilterType type) : + TerrainGenerator::LayerItem (tag), + m_type (type), + m_featherFunction (TGFF_linear), + m_featherDistance (0.f) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::Filter::~Filter () +{ +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Filter::needsNormals () const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Filter::needsShaders () const +{ + return false; +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::Affector +// +TerrainGenerator::Affector::Affector (const Tag tag, const TerrainGeneratorAffectorType type) : + TerrainGenerator::LayerItem (tag), + m_type (type) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::Affector::~Affector () +{ +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Affector::affectsHeight () const +{ + return false; +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Affector::affectsShader () const +{ + return false; +} + +float TerrainGenerator::Affector::isWithin (float worldX, float worldZ) const +{ + UNREF(worldX); + UNREF(worldZ); + return 0.0f; +} + +//------------------------------------------------------------------- +// +// TerrainGenerator::Layer::ProfileData +// + +TerrainGenerator::Layer::ProfileData::ProfileData () : + timeInOverhead (0), + timeInBoundaries (0), + timeInFilters (0), + timeInAffectors (0), + timeInSubLayers (0) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::Layer::ProfileData::~ProfileData () +{ +} + +//------------------------------------------------------------------- + +float TerrainGenerator::Layer::ProfileData::getLayerTime () const +{ + return + timeInOverhead + + timeInBoundaries + + timeInFilters + + timeInAffectors; +} + +//------------------------------------------------------------------- + +float TerrainGenerator::Layer::ProfileData::getTotalTime () const +{ + return getLayerTime () + timeInSubLayers; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::ProfileData::reset () +{ + timeInOverhead = 0; + timeInBoundaries = 0; + timeInFilters = 0; + timeInAffectors = 0; + timeInSubLayers = 0; +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Layer::ProfileData::isWorthCounting () const +{ + const float minimumTime = 0.001f; + + return + timeInOverhead > minimumTime || + timeInBoundaries > minimumTime || + timeInFilters > minimumTime || + timeInAffectors > minimumTime || + timeInSubLayers > minimumTime; +} + + +//------------------------------------------------------------------- +// +// TerrainGenerator::Layer +// + +TerrainGenerator::Layer::Layer () : + LayerItem (TAG_LAYR), + m_boundaryList (), + m_filterList (), + m_affectorList (), + m_subLayerList(), + m_hasActiveBoundaries (false), + m_hasActiveFilters (false), + m_hasActiveAffectors (false), + m_hasUnprunedAffectors(false), + m_hasActiveLayers (false), + m_hasUnprunedLayers(false), + m_invertBoundaries (false), + m_invertFilters (false), + m_useExtent (false), + m_extent (), + m_modificationHeight (0.f), + m_expanded (false), + m_notes (0), + m_profileData () +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::Layer::~Layer () +{ + if (m_notes) + { + delete [] m_notes; + m_notes = 0; + } + + int i; + for (i = 0; i < m_boundaryList.getNumberOfElements (); i++) + { + delete m_boundaryList [i]; + m_boundaryList [i] = 0; + } + + m_boundaryList.clear (); + + for (i = 0; i < m_filterList.getNumberOfElements (); i++) + { + delete m_filterList [i]; + m_filterList [i] = 0; + } + + m_filterList.clear (); + + for (i = 0; i < m_affectorList.getNumberOfElements (); i++) + { + delete m_affectorList [i]; + m_affectorList [i] = 0; + } + + m_affectorList.clear (); + + for (i = 0; i < m_subLayerList.getNumberOfElements (); i++) + { + delete m_subLayerList[i]; + m_subLayerList[i] = 0; + } + m_subLayerList.clear (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::setNotes (const char* const notes) +{ + if (m_notes) + { + delete [] m_notes; + m_notes = 0; + } + + if (notes) + m_notes = DuplicateString (notes); +} + +//---------------------------------------------------------------------- + +bool TerrainGenerator::Layer::computeHasPassableAffectors() const +{ + + { + for (int i = 0; i < m_affectorList.getNumberOfElements (); i++) + { + Affector const * const affector = m_affectorList [i]; + + if (affector->getType() == TGAT_passable) + { + return true; + } + } + } + + { + for (int i = 0; i < m_subLayerList.getNumberOfElements (); i++) + { + if (m_subLayerList[i]->computeHasPassableAffectors()) + return true; + } + } + + return false; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::addBoundary (Boundary* const boundary) +{ + m_boundaryList.add (boundary); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeBoundary (const int index) +{ + delete m_boundaryList [index]; + + m_boundaryList.removeIndexAndCompactList (index); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeBoundary (const Boundary* const boundary, const bool doDelete) +{ + //-- find boundary in list + int i; + for (i = 0; i < m_boundaryList.getNumberOfElements (); i++) + if (m_boundaryList [i] == boundary) + { + if (doDelete) + delete m_boundaryList [i]; + + m_boundaryList [i] = 0; + + break; + } + + DEBUG_FATAL (i == m_boundaryList.getNumberOfElements (), ("boundary not found in boundary list")); + m_boundaryList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::addFilter (Filter* const filter) +{ + m_filterList.add (filter); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeFilter (const int index) +{ + delete m_filterList [index]; + + m_filterList.removeIndexAndCompactList (index); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeFilter (const Filter* const filter, const bool doDelete) +{ + //-- find filter in list + int i; + for (i = 0; i < m_filterList.getNumberOfElements (); i++) + if (m_filterList [i] == filter) + { + if (doDelete) + delete m_filterList [i]; + + m_filterList [i] = 0; + + break; + } + + DEBUG_FATAL (i == m_filterList.getNumberOfElements (), ("filter not found in filter list")); + m_filterList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::addAffector (Affector* const affector) +{ + m_affectorList.add (affector); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeAffector (const int index) +{ + delete m_affectorList [index]; + + m_affectorList.removeIndexAndCompactList (index); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeAffector (const Affector* const affector, const bool doDelete) +{ + //-- find affector in list + int i; + for (i = 0; i < m_affectorList.getNumberOfElements (); i++) + if (m_affectorList [i] == affector) + { + if (doDelete) + delete m_affectorList [i]; + + m_affectorList [i] = 0; + + break; + } + + DEBUG_FATAL (i == m_affectorList.getNumberOfElements (), ("affector not found in affector list")); + m_affectorList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::prepare () +{ + m_hasActiveBoundaries = false; + { + int i; + for (i = 0; i < m_boundaryList.getNumberOfElements (); ++i) + { + if (m_boundaryList[i]->isActive ()) + { + m_hasActiveBoundaries=true; + + m_boundaryList [i]->prepare (); + } + } + } + + m_hasActiveFilters = false; + { + int i; + for (i = 0; i < m_filterList.getNumberOfElements (); ++i) + { + if (m_filterList [i]->isActive ()) + { + m_hasActiveFilters=true; + + m_filterList [i]->prepare (); + } + } + } + + m_hasActiveAffectors = false; + { + int i; + for (i = 0; i < m_affectorList.getNumberOfElements (); ++i) + { + if (m_affectorList [i]->isActive ()) + { + m_hasActiveAffectors=true; + + m_affectorList [i]->prepare (); + } + } + } + + m_hasActiveLayers = false; + { + int i; + for (i = 0; i < m_subLayerList.getNumberOfElements (); ++i) + { + if (m_subLayerList[i]->isActive()) + { + m_hasActiveLayers=true; + + m_subLayerList[i]->prepare (); + } + } + } +} + +//------------------------------------------------------------------- +void TerrainGenerator::Layer::_oldBoundaryTest(float &fuzzyTest, float worldX, float worldZ) const +{ + fuzzyTest = 0.f; + + //-- see if it is within any of the boundaries (if any) + bool hasActiveBoundaries = false; + + if (m_hasActiveBoundaries) + { + int i; + for (i = 0; i < m_boundaryList.getNumberOfElements (); i++) + { + if (m_boundaryList [i]->isActive ()) + { + hasActiveBoundaries = true; + + const Feather feather (m_boundaryList [i]->getFeatherFunction ()); + + const float amount = m_boundaryList [i]->isWithin (worldX, worldZ); + DEBUG_FATAL (amount < 0.f || amount > 1.f, ("amount out of range [0-1] %1.2f", amount)); + + fuzzyTest = FuzzyOr (fuzzyTest, feather.feather (0.f, 1.f, amount)); + if (fuzzyTest == 1.f) + break; + } + } + + } + + if (!hasActiveBoundaries) + { + fuzzyTest = 1.f; + } +} + +//------------------------------------------------------------------- + +bool TerrainGenerator::Layer::prune(unsigned &mapMask, const Rectangle2d &chunkExtentIUO) +{ + m_hasUnprunedLayers=false; + m_hasUnprunedAffectors=false; + + // ------------------------------------------------------------------------ + //-- if there are no affectors and no layers, don't do anything + if (!m_hasActiveAffectors && !m_hasActiveLayers) + { + setPruned(true); + return true; + } + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + //-- if the chunk is nowhere near the layer, don't do anything + if (m_useExtent && !m_extent.intersects(chunkExtentIUO)) + { + setPruned(true); + return true; + } + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + if (m_hasActiveLayers) + { + for (int i = m_subLayerList.getNumberOfElements()-1; i >=0 ; i--) + { + Layer * layer = m_subLayerList[i]; + if (!layer->prune(mapMask, chunkExtentIUO)) + { + m_hasUnprunedLayers=true; + } + } + } + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + if (m_hasActiveAffectors) + { + for (int i = m_affectorList.getNumberOfElements()-1; i>=0 ; i--) + { + Affector *a = m_affectorList[i]; + + bool isPruned = !a->isActive(); + if (!isPruned) + { + unsigned maps = a->getAffectedMaps(); + isPruned = (maps&mapMask)==0; + } + /* + if (isPruned) + { + REPORT_LOG_PRINT(true, ("Affector pruned!.\n")); + } + */ + a->setPruned(isPruned); + if (!a->isPruned()) + { + m_hasUnprunedAffectors=true; + } + } + } + // ------------------------------------------------------------------------ + + const bool newPruned = !m_hasUnprunedAffectors && !m_hasUnprunedLayers; + + // ------------------------------------------------------------------------ + // update the map mask for any filter needs. + if (!newPruned && m_hasActiveFilters) + { + for (int i = 0; i < m_filterList.getNumberOfElements(); i++) + { + Filter *f = m_filterList[i]; + if (!f->isActive()) + { + continue; + } + if (f->needsNormals()) + { + mapMask |= (TGM_height | TGM_vertexNormal); + break; + } + } + if (m_hasActiveAffectors) + { + for (int i = 0; i < m_filterList.getNumberOfElements(); i++) + { + Filter *f = m_filterList[i]; + if (!f->isActive()) + { + continue; + } + if (f->needsShaders()) + { + mapMask |= TGM_shader; + break; + } + } + } + } + // ------------------------------------------------------------------------ + + // ------------------------------------------------------------------------ + setPruned(newPruned); + return newPruned; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::affect (const float * previousAmountMap, const GeneratorChunkData& generatorChunkData) const +{ + //----------------------------------------------------------------------- + //-- scan filters to see if we need to generate plane and vertex normals + if (m_hasActiveFilters) + { + for (int i = 0; i < m_filterList.getNumberOfElements (); i++) + { + if (m_filterList [i]->isActive () && m_filterList [i]->needsNormals ()) + { + if (generatorChunkData.normalsDirtyIUO) + { + TerrainGenerator::generatePlaneAndVertexNormals (generatorChunkData); + + generatorChunkData.normalsDirtyIUO = false; + } + + break; + } + } + + //----------------------------------------------------------------------- + //-- scan filters to see if we need to stamp shader families + if (m_hasActiveAffectors) + { + //-- synchronize shader children + for (int i = 0; i < m_filterList.getNumberOfElements (); i++) + { + if (m_filterList [i]->isActive () && m_filterList [i]->needsShaders ()) + { + if (generatorChunkData.shadersDirtyIUO) + { + synchronizeShaders (generatorChunkData); + + generatorChunkData.shadersDirtyIUO = false; + } + + break; + } + } + } + //----------------------------------------------------------------------- + } + //----------------------------------------------------------------------- + + const bool onlyHasSubLayers = !m_hasActiveBoundaries && !m_hasActiveFilters && !m_hasActiveAffectors; + const int numberOfPoles = generatorChunkData.numberOfPoles; + + //----------------------------------------------------------------------- + //-- only allocate the amount map if we have sublayers. the amount map is used for feathering of sublayers + float *amountMap=0; + if (m_hasActiveLayers && !onlyHasSubLayers) + { + amountMap=(float *)_alloca(numberOfPoles*numberOfPoles*sizeof(*amountMap)); + } + //----------------------------------------------------------------------- + + bool shouldAffectSubLayers = onlyHasSubLayers; + if (!onlyHasSubLayers) + { + //--------------------------------------------------------------------------------------------- + float *boundaryMap=0; + if (m_hasActiveBoundaries) + { + for (int i = 0; i < m_boundaryList.getNumberOfElements(); i++) + { + Boundary *b = m_boundaryList[i]; + if (!b->isActive()) + { + continue; + } + + if (!boundaryMap) + { + const int boundaryMapSize=numberOfPoles*numberOfPoles*sizeof(*boundaryMap); + boundaryMap = (float *)_alloca(boundaryMapSize); + memset(boundaryMap, 0, boundaryMapSize); + } + + b->scanConvertGT(boundaryMap, generatorChunkData.chunkExtentIUO, numberOfPoles); + } + } + //--------------------------------------------------------------------------------------------- + + const bool invertBoundaries=m_invertBoundaries; + const float distanceBetweenPoles = generatorChunkData.distanceBetweenPoles; + for (int z = 0; z < numberOfPoles; z++) + { + const int rowIndex = z * numberOfPoles; + + const float worldZ = generatorChunkData.start.z + static_cast(z)*distanceBetweenPoles; + const float *previousAmountRow = previousAmountMap + rowIndex; + + for (int x = 0; x < numberOfPoles; x++) + { + const float worldX = generatorChunkData.start.x + static_cast(x)*distanceBetweenPoles; + const float previousAmount = previousAmountRow[x]; + + float fuzzyTest; + //------------------------------------------------------------------------------------- + if (boundaryMap) + { + fuzzyTest=boundaryMap[rowIndex + x]; + } + else + { + fuzzyTest=1.0; + } + //------------------------------------------------------------------------------------- + //float _fuzzyTest; + //_oldBoundaryTest(_fuzzyTest, worldX, worldZ); + //DEBUG_FATAL(fabs(_fuzzyTest-fuzzyTest)>1e-6, ("")); + //------------------------------------------------------------------------------------- + + if (invertBoundaries) + { + fuzzyTest = 1.f - fuzzyTest; + } + + DEBUG_FATAL (fuzzyTest < 0.f || fuzzyTest > 1.f, ("Boundary tests returned invalid value: %1.3f", fuzzyTest)); + + if (fuzzyTest > 0.f) + { + //-- see if it passes all filters (if any) + if (m_hasActiveFilters) + { + int i; + for (i = 0; i < m_filterList.getNumberOfElements (); i++) + { + if (m_filterList [i]->isActive ()) + { + + if(m_filterList[i]->getType() == TGFT_bitmap) // special case the bitmap filter because of boundaries + { + FilterBitmap *filterBitmap = safe_cast(m_filterList[i]); + filterBitmap->setExtent(m_extent); + } + + const Feather feather (m_filterList [i]->getFeatherFunction ()); + + const float amount = m_filterList [i]->isWithin (worldX, worldZ, x, z, generatorChunkData); + + DEBUG_FATAL (amount < 0.f || amount > 1.f, ("amount out of range [0-1] %1.2f", amount)); + + fuzzyTest = FuzzyAnd (fuzzyTest, feather.feather (0.f, 1.f, amount)); + + if (fuzzyTest == 0.f) + break; + + } + } + + } + + DEBUG_FATAL (fuzzyTest < 0.f || fuzzyTest > 1.f, ("Filter tests returned invalid value: %1.3f", fuzzyTest)); + + if (m_invertFilters) + { + fuzzyTest = 1.f - fuzzyTest; + } + + if (fuzzyTest > 0.f) + { + //-- there was at least one fuzzy test valid here, so we should affect sublayers + shouldAffectSubLayers = true; + + //-- run all affectors + if (m_hasUnprunedAffectors) + { + for (int i = 0; i < m_affectorList.getNumberOfElements (); i++) + { + Affector *a = m_affectorList[i]; + if (!a->isPruned()) + { + a->affect (worldX, worldZ, x, z, fuzzyTest * previousAmount, generatorChunkData); + + if (a->affectsHeight()) + { + generatorChunkData.normalsDirtyIUO = true; + } + + if (a->affectsShader()) + { + generatorChunkData.shadersDirtyIUO = true; + } + } + } + } + } + } + + if (amountMap) + { + amountMap[rowIndex + x]=fuzzyTest * previousAmount; + } + } + } + } + + //-- now affect the layers + if (shouldAffectSubLayers && m_hasActiveLayers) + { + for (int i = 0; i < m_subLayerList.getNumberOfElements (); i++) + { + const Layer *l = m_subLayerList[i]; + if (!l->isPruned()) + { + l->affect(onlyHasSubLayers ? previousAmountMap : amountMap, generatorChunkData); + } + } + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_ACTN (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_ACTN_0000 (iff, terrainGenerator); + break; + + case TAG_0001: + load_ACTN_0001 (iff, terrainGenerator); + break; + + case TAG_0002: + load_ACTN_0002 (iff, terrainGenerator); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_ACTN_0000 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_ACTN_0001 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + + setInvertBoundaries (iff.read_int32 () != 0); + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_ACTN_0002 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + + setInvertBoundaries (iff.read_int32 () != 0); + setInvertFilters (iff.read_int32 () != 0); + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::addLayer (Layer* const layer) +{ + m_subLayerList.add (layer); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeLayer (const int index) +{ + delete m_subLayerList [index]; + + m_subLayerList.removeIndexAndCompactList (index); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::removeLayer (const Layer* const layer, const bool doDelete) +{ + //-- find layer in list + int i; + for (i = 0; i < m_subLayerList.getNumberOfElements (); i++) + if (m_subLayerList[i] == layer) + { + if (doDelete) + delete m_subLayerList[i]; + + m_subLayerList[i] = 0; + + break; + } + + DEBUG_FATAL (i == m_subLayerList.getNumberOfElements (), ("layer not found in layer list")); + m_subLayerList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::promoteLayer (const Layer* const layer) +{ + //-- find layer in layer list + int i; + for (i = 0; i < m_subLayerList.getNumberOfElements (); i++) + if (m_subLayerList[i] == layer) + break; + + //-- if found and promote-able + if (i < m_subLayerList.getNumberOfElements ()) + if (i < m_subLayerList.getNumberOfElements () - 1) + std::swap (m_subLayerList[i], m_subLayerList[i + 1]); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::demoteLayer (const Layer* const layer) +{ + //-- find layer in layer list + int i; + for (i = 0; i < m_subLayerList.getNumberOfElements (); i++) + if (m_subLayerList[i] == layer) + break; + + //-- if found and demote-able + if (i < m_subLayerList.getNumberOfElements ()) + if (i > 0) + std::swap (m_subLayerList[i], m_subLayerList[i - 1]); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::calculateExtent () +{ + m_useExtent = false; + + if (!m_invertBoundaries) + { + //-- set extent to extreme inverse + m_extent.x0 = FLT_MAX; + m_extent.y0 = FLT_MAX; + m_extent.x1 = -FLT_MAX; + m_extent.y1 = -FLT_MAX; + + //-- check boundaries + int i; + for (i = 0; i < getNumberOfBoundaries (); i++) + { + Boundary* boundary = getBoundary (i); + + if (boundary->isActive ()) + { + m_useExtent = true; + + boundary->expand (m_extent); + } + } + + //-- run through all layers + for (i = 0; i < getNumberOfLayers (); i++) + if (getLayer (i)->isActive ()) + getLayer (i)->calculateExtent (); + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::setModificationHeight (float const modificationHeight) +{ + m_modificationHeight = modificationHeight; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_LAYR); + + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff, terrainGenerator); + break; + + case TAG_0001: + load_0001 (iff, terrainGenerator); + break; + + case TAG_0002: + load_0002 (iff, terrainGenerator); + break; + + case TAG_0003: + load_0003 (iff, terrainGenerator); + break; + + case TAG_0004: + load_0004 (iff, terrainGenerator); + break; + + default: + { + char tagBuffer [5]; + ConvertTagToString (iff.getCurrentName (), tagBuffer); + + char buffer [128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("unknown layer type %s/%s", buffer, tagBuffer)); + } + break; + } + + iff.exitForm (TAG_LAYR); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_0000 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0000); + + //-- load the base data + LayerItem::load (iff); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + iff.enterForm (TAG_ACTN); + + Layer* layer = new Layer (); + layer->load_ACTN (iff, terrainGenerator); + m_subLayerList.add(layer); + + iff.exitForm (TAG_ACTN); + } //lint !e429 //-- layer has not been freed or returned + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_0001 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0001); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + + setInvertBoundaries (iff.read_int32 () != 0); + setInvertFilters (iff.read_int32 () != 0); + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0001); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_0002 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0002); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + + setInvertBoundaries (iff.read_int32 () != 0); + setInvertFilters (iff.read_int32 () != 0); + setExpanded (iff.read_int32 () != 0); + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0002); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_0003 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0003); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + + setInvertBoundaries (iff.read_int32 () != 0); + setInvertFilters (iff.read_int32 () != 0); + setExpanded (iff.read_int32 () != 0); + + char* notes = iff.read_string (); + setNotes (notes); + delete [] notes; + notes = 0; + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0003); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::load_0004 (Iff& iff, TerrainGenerator* const terrainGenerator) +{ + iff.enterForm (TAG_0004); + + //-- load the base data + LayerItem::load (iff); + + //-- load the layer data + iff.enterChunk (TAG_ADTA); + setInvertBoundaries (iff.read_int32 () != 0); + setInvertFilters (iff.read_int32 () != 0); + + { + const int unused = iff.read_int32 (); + UNREF (unused); + } + + setExpanded (iff.read_int32 () != 0); + + char* notes = iff.read_string (); + setNotes (notes); + delete [] notes; + notes = 0; + + iff.exitChunk (TAG_ADTA); + + //-- load specific data + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + //-- load boundaries, filters, and/or affectors + TerrainGeneratorLoader::loadLayerItem (iff, terrainGenerator, this); + } + + iff.exitForm (TAG_0004); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::save (Iff& iff) const +{ + iff.insertForm (TAG_LAYR); + + //-- save layer + iff.insertForm (TAG_0003); //-- write 0005 next + + LayerItem::save (iff); + + //-- save the layer data + iff.insertChunk (TAG_ADTA); + + iff.insertChunkData (getInvertBoundaries () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getInvertFilters () ? static_cast (1) : static_cast (0)); + iff.insertChunkData (getExpanded () ? static_cast (1) : static_cast (0)); + iff.insertChunkString (getNotes () ? getNotes () : ""); + + iff.exitChunk (TAG_ADTA); + + //-- save boundaries, filters, and affectors + int n = m_boundaryList.getNumberOfElements (); + int i; + for (i = 0; i < n; i++) + { + iff.insertForm (m_boundaryList [i]->getTag ()); + + m_boundaryList [i]->save (iff); + + iff.exitForm (m_boundaryList [i]->getTag ()); + } + + n = m_filterList.getNumberOfElements (); + for (i = 0; i < n; i++) + { + iff.insertForm (m_filterList [i]->getTag ()); + + m_filterList [i]->save (iff); + + iff.exitForm (m_filterList [i]->getTag ()); + } + + n = m_affectorList.getNumberOfElements (); + for (i = 0; i < n; i++) + { + iff.insertForm (m_affectorList [i]->getTag ()); + + m_affectorList [i]->save (iff); + + iff.exitForm (m_affectorList [i]->getTag ()); + } + + n = m_subLayerList.getNumberOfElements (); + for (i = 0; i < n; i++) + { + m_subLayerList[i]->save (iff); + } + + iff.exitForm (TAG_0003); + + iff.exitForm (TAG_LAYR); +} + +//------------------------------------------------------------------- +// +// TerrainGenerator +// +TerrainGenerator::TerrainGenerator () : + m_shaderGroup (), + m_floraGroup (), + m_radialGroup (), + m_environmentGroup (), + m_fractalGroup (), + m_bitmapGroup (), + m_layerList (), + m_sampleMaps(unsigned(TGM_ALL)), + m_hasPassableAffectors(false), + m_groupsPrepared (false) +{ +} + +//------------------------------------------------------------------- + +TerrainGenerator::~TerrainGenerator () +{ + reset (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::reset () +{ + //-- delete shader group + m_shaderGroup.removeAllFamilies (); + + //-- delete flora group + m_floraGroup.removeAllFamilies (); + + //-- delete radial group + m_radialGroup.removeAllFamilies (); + + //-- delete environment group + m_environmentGroup.removeAllFamilies (); + + //-- delete fractal group + m_fractalGroup.reset (); + + //-- delete bitmap group + m_bitmapGroup.reset (); + + //-- delete layerList + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + { + delete m_layerList [i]; + m_layerList [i] = 0; + } + + m_layerList.clear (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::setMapsToSample(unsigned TGM_flags) +{ + m_sampleMaps = TGM_flags; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::addLayer (Layer* const layer) +{ + m_layerList.add (layer); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::removeLayer (const int index) +{ + delete m_layerList [index]; + + m_layerList.removeIndexAndCompactList (index); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::removeLayer (Layer* const layer, const bool doDelete) +{ + //-- find layer in list + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + if (m_layerList [i] == layer) + { + if (doDelete) + delete layer; + + m_layerList [i] = 0; + + break; + } + + DEBUG_FATAL (i == m_layerList.getNumberOfElements (), ("layer not found in layer list")); + m_layerList.removeIndexAndCompactList (i); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::affect (const GeneratorChunkData& generatorChunkData) const +{ + int i; + + float *const amountMap = (float *)_alloca(generatorChunkData.numberOfPoles*generatorChunkData.numberOfPoles*sizeof(*amountMap)); + const int totalPoles=generatorChunkData.numberOfPoles*generatorChunkData.numberOfPoles; + for (i=0;i (generatorChunkData.numberOfPoles - 1) * generatorChunkData.distanceBetweenPoles); + generatorChunkData.chunkExtentIUO.y1 = generatorChunkData.chunkExtentIUO.y0 + (static_cast (generatorChunkData.numberOfPoles - 1) * generatorChunkData.distanceBetweenPoles); + + // ------------------------------------------------------------------ + + unsigned sampleMaps = m_sampleMaps; + + if (generatorChunkData.isLegacyMode()) + { + sampleMaps |= + ( TGM_shader + | TGM_floraStaticCollidable + | TGM_floraStaticNonCollidable + | TGM_floraDynamicNear + | TGM_floraDynamicFar + ); + } + + if (sampleMaps & (TGM_vertexPosition | TGM_vertexNormal)) + { + sampleMaps|=TGM_height; + } + + for (i = m_layerList.getNumberOfElements()-1; i>=0 ; i--) + { + Layer *l = m_layerList[i]; + l->prune(sampleMaps, generatorChunkData.chunkExtentIUO); + } + + // ------------------------------------------------------------------ + + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + { + Layer *l = m_layerList[i]; + if (!l->isPruned()) + { + l->affect(amountMap, generatorChunkData); + } + } + + // ------------------------------------------------------------------ + + if ( (sampleMaps & TGM_vertexNormal)!=0 + && generatorChunkData.normalsDirtyIUO + ) + { + TerrainGenerator::generatePlaneAndVertexNormals (generatorChunkData); + + generatorChunkData.normalsDirtyIUO = false; + } + + if ( (sampleMaps & TGM_vertexPosition) != 0) + { + _generateVertexPositions(generatorChunkData); + } + + if ( (sampleMaps & TGM_shader)!=0 + && generatorChunkData.shadersDirtyIUO + ) + { + TerrainGenerator::synchronizeShaders (generatorChunkData); + + generatorChunkData.shadersDirtyIUO = false; + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::prepare () +{ + m_groupsPrepared = false; + + //-- calculate extent information + calculateExtent (); + + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); ++i) + if (m_layerList [i]->isActive ()) + m_layerList [i]->prepare (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::generateChunk (const GeneratorChunkData& generatorChunkData) const +{ + //-- + if (!m_groupsPrepared) + { + m_groupsPrepared = true; + const_cast (this)->m_fractalGroup.prepare (generatorChunkData.numberOfPoles, generatorChunkData.numberOfPoles); + } + + generatorChunkData.validate (); + + //-- clear all maps + generatorChunkData.heightMap->makeZero (); + generatorChunkData.colorMap->makeValue (PackedRgb::solidWhite); + generatorChunkData.shaderMap->makeValue (m_shaderGroup.getDefaultShader ()); + generatorChunkData.floraStaticCollidableMap->makeValue (m_floraGroup.getDefaultFlora ()); + generatorChunkData.floraStaticNonCollidableMap->makeValue (m_floraGroup.getDefaultFlora ()); + generatorChunkData.floraDynamicNearMap->makeValue (m_radialGroup.getDefaultRadial ()); + generatorChunkData.floraDynamicFarMap->makeValue (m_radialGroup.getDefaultRadial ()); + generatorChunkData.environmentMap->makeValue (m_environmentGroup.getDefaultEnvironment ()); + generatorChunkData.excludeMap->makeZero (); + generatorChunkData.passableMap->makeValue(true); + + if (generatorChunkData.m_legacyRandomGenerator) + { + //-- use an arbitrary hashing function of x,z + const uint32 seed = static_cast + ((sqr (generatorChunkData.start.x) - (0.5f * generatorChunkData.start.x)) + + (sqr (generatorChunkData.start.z) - (1.5f * generatorChunkData.start.z))); + + generatorChunkData.m_legacyRandomGenerator->setSeed (seed); + } + + //-- run the affectors + affect (generatorChunkData); +} + +//---------------------------------------------------------------------- + +bool TerrainGenerator::hasPassableAffectors() const +{ + return m_hasPassableAffectors; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::_generateVertexPositions(const GeneratorChunkData& generatorChunkData) const +{ + // + //-- cache all variables + // + const Array2d* const heightMap = generatorChunkData.heightMap; + Array2d* const vertexPositionMap = generatorChunkData.vertexPositionMap; + const int numberOfPoles = generatorChunkData.numberOfPoles; + const float distanceBetweenPoles = generatorChunkData.distanceBetweenPoles; + const Vector start = generatorChunkData.start; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- build vertex position buffer + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + for (int z = 0; z < numberOfPoles; z++) + { + const float posZ = start.z + (z * distanceBetweenPoles); + const float *heightRow = &heightMap->getData(0, z); + Vector *positionRow = &vertexPositionMap->getData(0, z); + + float fx = start.x; + for (int x = 0; x < numberOfPoles; x++, fx+=distanceBetweenPoles) + { + Vector &v=positionRow[x]; + + v.x=fx; + v.y=start.y + heightRow[x]; + v.z=posZ; + } + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::generatePlaneAndVertexNormals (const GeneratorChunkData& generatorChunkData) +{ + // + //-- cache all variables + // + const Array2d* const heightMap = generatorChunkData.heightMap; + Array2d* const vertexNormalMap = generatorChunkData.vertexNormalMap; + const int numberOfPoles = generatorChunkData.numberOfPoles; + const float distanceBetweenPoles = generatorChunkData.distanceBetweenPoles; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- build planeArray is used to build the vertex normal buffer and collision + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + Vector normal_ur; + Vector normal_ll; + + //-- zero out the plane data + vertexNormalMap->makeZero (); + + for (int z = 0; z < numberOfPoles - 1; z++) + { + const float *heightRow0 = &heightMap->getData(0, z); + const float *heightRow1 = &heightMap->getData(0, z+1); + + Vector *normalRow0 = &vertexNormalMap->getData(0, z); + Vector *normalRow1 = &vertexNormalMap->getData(0, z+1); + + for (int x = 0; x < numberOfPoles - 1; x++) + { + //-- get the float vectors from the height buffer + const Vector v20(-distanceBetweenPoles, heightRow1[x]-heightRow0[x+1], distanceBetweenPoles); + const Vector v01( distanceBetweenPoles, heightRow1[x+1]-heightRow1[x], 0); + const Vector v32( distanceBetweenPoles, heightRow0[x+1]-heightRow0[x], 0); + + //-- grab normals + //-- FIXME_ALS - this doesn't match the tile data organization + normal_ur = v20.cross(v01); + normal_ll = v20.cross(v32); + + //-- add normals to vertex normal buffer at ur (0, 1, 2) + normalRow1[x] += normal_ur; //vertexNormalMap->getData (x, z + 1) += normal_ur; + normalRow1[x+1] += normal_ur; //vertexNormalMap->getData (x + 1, z + 1) += normal_ur; + normalRow0[x+1] += normal_ur; //vertexNormalMap->getData (x + 1, z) += normal_ur; + + //-- add normals to vertex normal buffer at ll (2, 3, 0) + normalRow0[x+1] += normal_ll; //vertexNormalMap->getData (x + 1, z) += normal_ll; + normalRow0[x] += normal_ll; //vertexNormalMap->getData (x, z) += normal_ll; + normalRow1[x] += normal_ll; //vertexNormalMap->getData (x, z + 1) += normal_ll; + } + } + } + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + //-- make pass on vertexNormalMap to normalize all vertex normals + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + Vector *normals = &vertexNormalMap->getData(0,0); + + const int totalPoles = numberOfPoles*numberOfPoles; + const Vector *const normalsStop = normals + totalPoles; + + while (normals!=normalsStop) + { + const float mag = normals->magnitude(); + *normals *= 1.0f / mag; + normals++; + } + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::synchronizeShaders (const GeneratorChunkData& generatorChunkData) +{ + const int originOffset = generatorChunkData.originOffset; + + const int preOffset = 2 - originOffset; + const int postOffset = originOffset; + + Array2d *const shaderMap = generatorChunkData.shaderMap; + + int upperPad = generatorChunkData.upperPad - 1; + if (upperPad<0) + { + upperPad=0; + } + + const int maxHeight = ((shaderMap->getHeight()-postOffset-1)|3)-preOffset+1; + int height = shaderMap->getHeight() - upperPad; + if (height>maxHeight) + { + height=maxHeight; + } + + const int maxWidth = ((shaderMap->getWidth()-postOffset-1)|3)-preOffset+1; + int width = shaderMap->getWidth() - upperPad; + if (width>maxWidth) + { + width=maxWidth; + } + + for (int z = 0; z < height; ++z) + { + int preOffsetZ = z + preOffset; + if (preOffsetZ<0) + { + preOffsetZ=0; + } + const int newZ = (preOffsetZ & ~3) + postOffset; + + const ShaderGroup::Info *srcRow = &shaderMap->getData(0, newZ); + ShaderGroup::Info *destRow = &shaderMap->getData(0, z); + + for (int x = 0; x < width; ++x) + { + int preOffsetX = x + preOffset; + if (preOffsetX<0) + { + preOffsetX=0; + } + const int newX = (preOffsetX & ~3) + postOffset; + + const ShaderGroup::Info old_sgi = destRow[x]; //shaderMap->getData (x, z); + + ShaderGroup::Info new_sgi = srcRow[newX]; //shaderMap->getData (newX, newZ); + + new_sgi.setChildChoice (old_sgi.getChildChoice ()); + + destRow[x]=new_sgi; //shaderMap->setData (x, z, new_sgi); + } + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::load (Iff& iff) +{ + iff.enterForm (TAG (T,G,E,N)); + + //-- specific load + switch (iff.getCurrentName ()) + { + case TAG_0000: + load_0000 (iff); + break; + + default: + { + char buffer[128]; + iff.formatLocation (buffer, sizeof (buffer)); + DEBUG_FATAL (true, ("bad version number at %s", buffer)); + } + break; + } + + iff.exitForm (TAG (T,G,E,N)); + + //-- prepare at least once after load (in case we're not running the tool) + prepare (); + + //-- check for passable affectors + + { + int n = m_layerList.getNumberOfElements (); + for (int i = 0; i < n && !m_hasPassableAffectors; i++) + { + m_hasPassableAffectors = m_layerList [i]->computeHasPassableAffectors(); + } + } +} + +//------------------------------------------------------------------- + +void TerrainGenerator::load_0000 (Iff& iff) +{ + iff.enterForm (TAG_0000); + + //-- load shader group (this allows creation of TerrainGenerator outside of terrain system) + m_shaderGroup.load (iff); + + //-- load flora group + m_floraGroup.load (iff); + + //-- load flora group + m_radialGroup.load (iff); + + //-- load environment group + m_environmentGroup.load (iff); + + //-- load fractal group + m_fractalGroup.load (iff); + + //-- load bitmap group + m_bitmapGroup.load(iff); + + //-- load layers + if (iff.enterForm (TAG (L,Y,R,S), true)) + { + int n = iff.getNumberOfBlocksLeft (); + int i; + for (i = 0; i < n; i++) + { + Layer* layer = new Layer (); + layer->load (iff, this); + addLayer (layer); + } //lint !e429 //-- layer has not been freed or returned + + iff.exitForm (TAG (L,Y,R,S)); + } + + iff.exitForm (TAG_0000); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::saveLayers (Iff& iff) const +{ + iff.insertForm (TAG (L,Y,R,S)); + + int n = m_layerList.getNumberOfElements (); + int i; + for (i = 0; i < n; i++) + m_layerList [i]->save (iff); + + iff.exitForm (TAG (L,Y,R,S)); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::save (Iff& iff) const +{ + iff.insertForm (TAG (T,G,E,N)); + + iff.insertForm (TAG_0000); + + //-- write shader group + m_shaderGroup.save (iff); + + //-- write flora group + m_floraGroup.save (iff); + + //-- write flora group + m_radialGroup.save (iff); + + //-- write environment group + m_environmentGroup.save (iff); + + //-- write fractal group + m_fractalGroup.save (iff); + + //-- write bitmap group + m_bitmapGroup.save(iff); + + //-- save layers + saveLayers (iff); + + iff.exitForm (TAG_0000); + + iff.exitForm (TAG (T,G,E,N)); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::promoteLayer (const Layer* const layer) +{ + //-- find layer in layer list + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + if (m_layerList [i] == layer) + break; + + //-- if found and promote-able + if (i < m_layerList.getNumberOfElements ()) + if (i < m_layerList.getNumberOfElements () - 1) + std::swap (m_layerList [i], m_layerList [i + 1]); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::demoteLayer (const Layer* const layer) +{ + //-- find layer in layer list + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + if (m_layerList [i] == layer) + break; + + //-- if found and demote-able + if (i < m_layerList.getNumberOfElements ()) + if (i > 0) + std::swap (m_layerList [i], m_layerList [i - 1]); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::calculateExtent () +{ + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + if (m_layerList [i]->isActive ()) + m_layerList [i]->calculateExtent (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::resetProfileData () +{ + m_profileData.reset (); + + int i; + for (i = 0; i < m_subLayerList.getNumberOfElements(); i++) + m_subLayerList[i]->resetProfileData (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::resetProfileData () +{ + int i; + for (i = 0; i < m_layerList.getNumberOfElements (); i++) + m_layerList [i]->resetProfileData (); +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::setFeatherFunction (const TerrainGeneratorFeatherFunction featherFunction) +{ + m_featherFunction = featherFunction; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Boundary::setFeatherDistance (const float featherDistance) +{ + m_featherDistance = featherDistance; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Filter::setFeatherFunction (const TerrainGeneratorFeatherFunction featherFunction) +{ + m_featherFunction = featherFunction; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Filter::setFeatherDistance (const float featherDistance) +{ + m_featherDistance = featherDistance; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::setInvertBoundaries (const bool invertBoundaries) +{ + m_invertBoundaries = invertBoundaries; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::setInvertFilters (const bool invertFilters) +{ + m_invertFilters = invertFilters; +} + +//------------------------------------------------------------------- + +void TerrainGenerator::Layer::setExpanded (const bool expanded) +{ + m_expanded = expanded; +} + +//------------------------------------------------------------------- + +const TerrainGenerator::Layer::ProfileData& TerrainGenerator::Layer::getProfileData () const +{ + return m_profileData; +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.h b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.h new file mode 100644 index 00000000..6ba55e0d --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGenerator.h @@ -0,0 +1,886 @@ +//=================================================================== +// +// TerrainGenerator.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//-- +// +// figure out: +// 1) if a layer is inactive, it shouldn't be loaded instead of tested +// before use +// +//=================================================================== + +#ifndef INCLUDED_TerrainGenerator_H +#define INCLUDED_TerrainGenerator_H + +//=================================================================== + +#include "sharedFoundation/ArrayList.h" +#include "sharedFoundation/Tag.h" +#include "sharedMath/Rectangle2d.h" +#include "sharedMath/Vector.h" +#include "sharedRandom/RandomGenerator.h" +#include "sharedTerrain/Array2d.h" +#include "sharedTerrain/BitmapGroup.h" +#include "sharedTerrain/EnvironmentGroup.h" +#include "sharedTerrain/FloraGroup.h" +#include "sharedTerrain/FractalGroup.h" +#include "sharedTerrain/RadialGroup.h" +#include "sharedTerrain/ShaderGroup.h" +#include "sharedTerrain/TerrainGeneratorType.h" + +class Shader; + +//=================================================================== + +class TerrainGenerator +{ +public: + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // GeneratorChunkData is used to request a chunk from the generator + // + struct GeneratorChunkData + { + public: + + //-- number of poles also represents the number of valid indices in the chunk maps + int originOffset; + int numberOfPoles; + int upperPad; + float distanceBetweenPoles; + + //-- offset into world space for left-rear corner of chunk to build (including the buffer zone) + Vector start; + + //-- numberOfPoles x numberOfPoles + Array2d* heightMap; + + //-- numberOfPoles x numberOfPoles + Array2d* colorMap; + + //-- since a tile is two poles, every other entry is skipped + Array2d* shaderMap; + + //-- map of flora per tile + Array2d* floraStaticCollidableMap; + + //-- map of flora per tile + Array2d* floraStaticNonCollidableMap; + + //-- map of radial flora per tile + Array2d* floraDynamicNearMap; + + //-- map of radial flora per tile + Array2d* floraDynamicFarMap; + + //-- map of environment block data per tile + Array2d* environmentMap; + + //-- used to calculate the plane data and vertex normals + Array2d* vertexPositionMap; + + //-- the normal at the vertex + Array2d* vertexNormalMap; + + //-- allows tiles to be excluded + Array2d* excludeMap; + + //-- allows tiles to be passable/not passable + Array2d* passableMap; + + //-- groups + const ShaderGroup* shaderGroup; + const FloraGroup* floraGroup; + const RadialGroup* radialGroup; + const EnvironmentGroup* environmentGroup; + const FractalGroup* fractalGroup; + const BitmapGroup* bitmapGroup; + + //-- provides random numbers for choosers and affectors + RandomGenerator *m_legacyRandomGenerator; + + //-- internal use only + mutable bool normalsDirtyIUO; + mutable bool shadersDirtyIUO; + mutable Rectangle2d chunkExtentIUO; + + private: + + GeneratorChunkData (const GeneratorChunkData& rhs); + GeneratorChunkData& operator= (const GeneratorChunkData& rhs); + + public: + + GeneratorChunkData(bool legacyMode); + ~GeneratorChunkData (); + + void validate () const; + + bool isLegacyMode() const { return m_legacyRandomGenerator!=0; } + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // CreateChunkBuffer is a scratchpad for generating terrain chunks + // + struct CreateChunkBuffer + { + public: + + //-- actual maps + Array2d heightMap; + Array2d colorMap; + Array2d shaderMap; + Array2d floraStaticCollidableMap; + Array2d floraStaticNonCollidableMap; + Array2d floraDynamicNearMap; + Array2d floraDynamicFarMap; + Array2d environmentMap; + Array2d vertexPositionMap; + Array2d vertexNormalMap; + Array2d excludeMap; + Array2d passableMap; + + private: + + CreateChunkBuffer (const CreateChunkBuffer& rhs); + CreateChunkBuffer& operator= (const CreateChunkBuffer& rhs); + + public: + + CreateChunkBuffer (); + ~CreateChunkBuffer (); + + void allocate (int poleCount); + + void validate () const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // LayerItem holds tool specific data for all Boundaries, Filters, Affectors, and Layers + // + class LayerItem + { + private: + + const Tag m_tag; + bool m_active; + bool m_pruned; + char* m_name; + + private: + + void load_0000 (Iff& iff); + void load_0001 (Iff& iff); + + private: + + LayerItem (); + LayerItem (const LayerItem& rhs); + LayerItem& operator= (const LayerItem& rhs); + + public: + + explicit LayerItem (Tag tag); + virtual ~LayerItem ()=0; + + Tag getTag () const; + + void setActive (bool active); + bool isActive () const; + + void setPruned(bool pruned) { m_pruned=pruned; } + bool isPruned() const { return m_pruned; } + + void setName (const char* name); + const char* getName () const; + + virtual void prepare (); + virtual void load (Iff& iff); + virtual void save (Iff& iff) const=0; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // + // Boundary is the interface for all boundary types. This could potentially + // be optimized by having the circle as the base type, and only checking + // isWithin for derived types if isWithin for the circle test passes first + // since the circle would be the fastest check. + // + class Boundary : public LayerItem + { + private: + + const TerrainGeneratorBoundaryType m_type; + + TerrainGeneratorFeatherFunction m_featherFunction; + float m_featherDistance; + + private: + + Boundary (); + Boundary (const Boundary& rhs); + Boundary& operator= (const Boundary& rhs); + + public: + + Boundary (Tag tag, TerrainGeneratorBoundaryType type); + virtual ~Boundary ()=0; + + TerrainGeneratorBoundaryType getType () const; + + TerrainGeneratorFeatherFunction getFeatherFunction () const; + void setFeatherFunction (TerrainGeneratorFeatherFunction featherFunction); + + float getFeatherDistance () const; + virtual void setFeatherDistance (float featherDistance); + + virtual void rotate (float angle); + virtual void rotate (float angle, const Vector2d& center); + virtual void translate (const Vector2d& translation); + virtual void scale (float scalar); + virtual float isWithin (float worldX, float worldZ) const=0; + virtual void expand (Rectangle2d& extent) const=0; + virtual const Vector2d getCenter () const=0; + + virtual bool intersects(const Rectangle2d& other) const=0; + virtual void scanConvertGT(float *o_data, const Rectangle2d &scanArea, int numberOfPoles) const; + + //-- run-time rule interface + virtual void setCenter (const Vector2d& center); + virtual void setRotation (float angle); + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Filter : public LayerItem + { + private: + + const TerrainGeneratorFilterType m_type; + + TerrainGeneratorFeatherFunction m_featherFunction; + float m_featherDistance; + + private: + + Filter (); + Filter (const Filter& rhs); + Filter& operator= (const Filter& rhs); + + public: + + Filter (Tag tag, TerrainGeneratorFilterType type); + virtual ~Filter ()=0; + + TerrainGeneratorFilterType getType () const; + + TerrainGeneratorFeatherFunction getFeatherFunction () const; + void setFeatherFunction (TerrainGeneratorFeatherFunction featherFunction); + + float getFeatherDistance () const; + virtual void setFeatherDistance (float featherDistance); + + virtual float isWithin (float worldX, float worldZ, int x, int z, const GeneratorChunkData& generatorChunkData) const=0; + + virtual bool needsNormals () const; + virtual bool needsShaders () const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Affector : public LayerItem + { + private: + + const TerrainGeneratorAffectorType m_type; + + private: + + Affector (); + Affector (const Affector& rhs); + Affector& operator= (const Affector& rhs); + + public: + + Affector (Tag tag, TerrainGeneratorAffectorType type); + virtual ~Affector ()=0; + + TerrainGeneratorAffectorType getType () const; + + virtual void affect (float worldX, float worldZ, int x, int z, float amount, const GeneratorChunkData& generatorChunkData) const=0; + virtual bool affectsHeight () const; + virtual bool affectsShader () const; + virtual unsigned getAffectedMaps() const=0; + virtual float isWithin (float worldX, float worldZ) const; + + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + class Layer : public LayerItem + { + public: + + struct ProfileData + { + public: + + float timeInOverhead; + float timeInBoundaries; + float timeInFilters; + float timeInAffectors; + float timeInSubLayers; + + public: + + ProfileData (); + ~ProfileData (); + + bool isWorthCounting () const; + float getLayerTime () const; + float getTotalTime () const; + + void reset (); + }; + + private: + + ArrayList m_boundaryList; + ArrayList m_filterList; + ArrayList m_affectorList; + ArrayList m_subLayerList; + + bool m_hasActiveBoundaries; + bool m_hasActiveFilters; + bool m_hasActiveAffectors; + bool m_hasUnprunedAffectors; + bool m_hasActiveLayers; + bool m_hasUnprunedLayers; + + bool m_invertBoundaries; + bool m_invertFilters; + + bool m_useExtent; + Rectangle2d m_extent; + + float m_modificationHeight; + + bool m_expanded; + + char* m_notes; + + private: + + mutable ProfileData m_profileData; + + private: + + void load_0000 (Iff& iff, TerrainGenerator* terrainGenerator); //lint !e1511 // member hides non-virt + void load_0001 (Iff& iff, TerrainGenerator* terrainGenerator); //lint !e1511 // member hides non-virt + void load_0002 (Iff& iff, TerrainGenerator* terrainGenerator); //lint !e1511 // member hides non-virt + void load_0003 (Iff& iff, TerrainGenerator* terrainGenerator); //lint !e1511 // member hides non-virt + void load_0004 (Iff& iff, TerrainGenerator* terrainGenerator); //lint !e1511 // member hides non-virt + + void load_ACTN (Iff& iff, TerrainGenerator* terrainGenerator); + void load_ACTN_0000 (Iff& iff, TerrainGenerator* terrainGenerator); + void load_ACTN_0001 (Iff& iff, TerrainGenerator* terrainGenerator); + void load_ACTN_0002 (Iff& iff, TerrainGenerator* terrainGenerator); + + private: + + Layer (const Layer& rhs); + Layer& operator= (const Layer& rhs); + + public: + + Layer (); + ~Layer (); + + void _oldBoundaryTest(float &fuzzyTest, float worldX, float worldZ) const; + + void affect (const float *previousAmountMap, const GeneratorChunkData& generatorChunkData) const; + virtual void prepare (); + virtual void load (Iff& iff, TerrainGenerator* terrainGenerator); + virtual void save (Iff& iff) const; + + virtual bool prune(unsigned &mapMask, const Rectangle2d &chunkExtentIUO); + + bool getInvertBoundaries () const; + void setInvertBoundaries (bool invertBoundaries); + + bool getInvertFilters () const; + void setInvertFilters (bool invertFilters); + + int getNumberOfBoundaries () const; + const Boundary* getBoundary (int index) const; + Boundary* getBoundary (int index); + void addBoundary (Boundary* boundary); + void removeBoundary (int index); + void removeBoundary (const Boundary* boundary, bool doDelete); + void promoteBoundary (const Boundary* boundary); + void demoteBoundary (const Boundary* boundary); + + int getNumberOfFilters () const; + const Filter* getFilter (int index) const; + Filter* getFilter (int index); + void addFilter (Filter* filter); + void removeFilter (int index); + void removeFilter (const Filter* filter, bool doDelete); + void promoteFilter (const Filter* filter); + void demoteFilter (const Filter* filter); + + int getNumberOfAffectors () const; + const Affector* getAffector (int index) const; + Affector* getAffector (int index); + void addAffector (Affector* affector); + void removeAffector (int index); + void removeAffector (const Affector* affector, bool doDelete); + + int getNumberOfLayers () const; + const Layer* getLayer (int index) const; + Layer* getLayer (int index); + void addLayer (Layer* layer); + void removeLayer (int index); + void removeLayer (const Layer* layer, bool doDelete); + void promoteLayer (const Layer* layer); + void demoteLayer (const Layer* layer); + + void calculateExtent (); + bool getUseExtent () const; + const Rectangle2d& getExtent () const; + + float getModificationHeight () const; + void setModificationHeight (float modificationHeight); + + //-- tool use only + void setExpanded (bool expanded); + bool getExpanded () const; + + void resetProfileData (); + const ProfileData& getProfileData () const; + + void setNotes (const char* notes); + const char* getNotes () const; + + bool computeHasPassableAffectors() const; + }; + + //- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +private: + + ShaderGroup m_shaderGroup; + FloraGroup m_floraGroup; + RadialGroup m_radialGroup; + EnvironmentGroup m_environmentGroup; + FractalGroup m_fractalGroup; + BitmapGroup m_bitmapGroup; + + ArrayList m_layerList; + + unsigned m_sampleMaps; + bool m_hasPassableAffectors; + +private: + + mutable bool m_groupsPrepared; + +private: + + void _generateVertexPositions(const GeneratorChunkData& generatorChunkData) const; + void affect (const GeneratorChunkData& generatorChunkData) const; + + void load_0000 (Iff& iff); + + void saveLayerList (Iff& iff, const ArrayList& layerList) const; + void saveLayers (Iff& iff) const; + + void calculateExtent (); + +private: + + TerrainGenerator (const TerrainGenerator& rhs); + TerrainGenerator& operator= (const TerrainGenerator& rhs); + +public: + + TerrainGenerator (); + ~TerrainGenerator (); + + // set which maps you are interested in. + // see the TerrainGeneratorMap bit flags + void setMapsToSample(unsigned TGM_flags); + + const ShaderGroup& getShaderGroup () const; + ShaderGroup& getShaderGroup (); + + const FloraGroup& getFloraGroup () const; + FloraGroup& getFloraGroup (); + + const RadialGroup& getRadialGroup () const; + RadialGroup& getRadialGroup (); + + const EnvironmentGroup& getEnvironmentGroup () const; + EnvironmentGroup& getEnvironmentGroup (); + + const FractalGroup& getFractalGroup () const; + FractalGroup& getFractalGroup (); + + const BitmapGroup& getBitmapGroup() const; + BitmapGroup& getBitmapGroup(); + + //-- layer interface + int getNumberOfLayers () const; + const Layer* getLayer (int index) const; + Layer* getLayer (int index); + void addLayer (Layer* layer); + void removeLayer (int index); + void removeLayer (Layer* layer, bool doDelete); + void promoteLayer (const Layer* layer); + void demoteLayer (const Layer* layer); + + void resetProfileData (); + + //-- reset the generator (clears shader groups and flora groups and removes all layers) + void reset (); + + //-- load the generator + void load (Iff& iff); + + //-- save the generator + void save (Iff& iff) const; + + //-- prepare should only be called from the tool and is used to validate the data before generation + void prepare (); + + //-- fills out data specific to a chunk + void generateChunk (const GeneratorChunkData& generatorChunkData) const; + + bool hasPassableAffectors() const; + +public: + + //-- used internally + static void generatePlaneAndVertexNormals (const GeneratorChunkData& generatorChunkData); + static void synchronizeShaders (const GeneratorChunkData& generatorChunkData); +}; + +//=================================================================== + +inline Tag TerrainGenerator::LayerItem::getTag () const +{ + return m_tag; +} + +//------------------------------------------------------------------- + +inline const char* TerrainGenerator::LayerItem::getName () const +{ + return m_name; +} + +//=================================================================== + +inline TerrainGeneratorBoundaryType TerrainGenerator::Boundary::getType () const +{ + return m_type; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorFeatherFunction TerrainGenerator::Boundary::getFeatherFunction () const +{ + return m_featherFunction; +} + +//------------------------------------------------------------------- + +inline float TerrainGenerator::Boundary::getFeatherDistance () const +{ + return m_featherDistance; +} + +//=================================================================== + +inline TerrainGeneratorFilterType TerrainGenerator::Filter::getType () const +{ + return m_type; +} + +//------------------------------------------------------------------- + +inline TerrainGeneratorFeatherFunction TerrainGenerator::Filter::getFeatherFunction () const +{ + return m_featherFunction; +} + +//------------------------------------------------------------------- + +inline float TerrainGenerator::Filter::getFeatherDistance () const +{ + return m_featherDistance; +} + +//=================================================================== + +inline TerrainGeneratorAffectorType TerrainGenerator::Affector::getType () const +{ + return m_type; +} + +//=================================================================== + +inline bool TerrainGenerator::Layer::getInvertBoundaries () const +{ + return m_invertBoundaries; +} + +//------------------------------------------------------------------- + +inline bool TerrainGenerator::Layer::getInvertFilters () const +{ + return m_invertFilters; +} + +//------------------------------------------------------------------- + +inline bool TerrainGenerator::Layer::getExpanded () const +{ + return m_expanded; +} + +//------------------------------------------------------------------- + +inline const char* TerrainGenerator::Layer::getNotes () const +{ + return m_notes; +} + +//------------------------------------------------------------------- + +inline bool TerrainGenerator::Layer::getUseExtent () const +{ + return m_useExtent; +} + +//------------------------------------------------------------------- + +inline const Rectangle2d& TerrainGenerator::Layer::getExtent () const +{ + return m_extent; +} + +//------------------------------------------------------------------- + +inline float TerrainGenerator::Layer::getModificationHeight () const +{ + return m_modificationHeight; +} + +//------------------------------------------------------------------- + +inline int TerrainGenerator::Layer::getNumberOfBoundaries () const +{ + return m_boundaryList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const TerrainGenerator::Boundary* TerrainGenerator::Layer::getBoundary (int index) const +{ + return m_boundaryList [index]; +} + +//------------------------------------------------------------------- + +inline TerrainGenerator::Boundary* TerrainGenerator::Layer::getBoundary (int index) +{ + return m_boundaryList [index]; +} + +//------------------------------------------------------------------- + +inline int TerrainGenerator::Layer::getNumberOfFilters () const +{ + return m_filterList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const TerrainGenerator::Filter* TerrainGenerator::Layer::getFilter (int index) const +{ + return m_filterList [index]; +} + +//------------------------------------------------------------------- + +inline TerrainGenerator::Filter* TerrainGenerator::Layer::getFilter (int index) +{ + return m_filterList [index]; +} + +//------------------------------------------------------------------- + +inline int TerrainGenerator::Layer::getNumberOfAffectors () const +{ + return m_affectorList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const TerrainGenerator::Affector* TerrainGenerator::Layer::getAffector (int index) const +{ + return m_affectorList [index]; +} + +//------------------------------------------------------------------- + +inline TerrainGenerator::Affector* TerrainGenerator::Layer::getAffector (int index) +{ + return m_affectorList [index]; +} + +//------------------------------------------------------------------- + +inline int TerrainGenerator::Layer::getNumberOfLayers () const +{ + return m_subLayerList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const TerrainGenerator::Layer* TerrainGenerator::Layer::getLayer (int index) const +{ + return m_subLayerList[index]; +} + +//------------------------------------------------------------------- + +inline TerrainGenerator::Layer* TerrainGenerator::Layer::getLayer (int index) +{ + return m_subLayerList[index]; +} + +//=================================================================== + +inline int TerrainGenerator::getNumberOfLayers () const +{ + return m_layerList.getNumberOfElements (); +} + +//------------------------------------------------------------------- + +inline const TerrainGenerator::Layer* TerrainGenerator::getLayer (int index) const +{ + return m_layerList [index]; +} + +//------------------------------------------------------------------- + +inline TerrainGenerator::Layer* TerrainGenerator::getLayer (int index) +{ + return m_layerList [index]; +} + +//------------------------------------------------------------------- + +inline const ShaderGroup& TerrainGenerator::getShaderGroup () const +{ + return m_shaderGroup; +} + +//------------------------------------------------------------------- + +inline ShaderGroup& TerrainGenerator::getShaderGroup () +{ + return m_shaderGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline const FloraGroup& TerrainGenerator::getFloraGroup () const +{ + return m_floraGroup; +} + +//------------------------------------------------------------------- + +inline FloraGroup& TerrainGenerator::getFloraGroup () +{ + return m_floraGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline const RadialGroup& TerrainGenerator::getRadialGroup () const +{ + return m_radialGroup; +} + +//------------------------------------------------------------------- + +inline RadialGroup& TerrainGenerator::getRadialGroup () +{ + return m_radialGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline const EnvironmentGroup& TerrainGenerator::getEnvironmentGroup () const +{ + return m_environmentGroup; +} + +//------------------------------------------------------------------- + +inline EnvironmentGroup& TerrainGenerator::getEnvironmentGroup () +{ + return m_environmentGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline const FractalGroup& TerrainGenerator::getFractalGroup () const +{ + return m_fractalGroup; +} + +//------------------------------------------------------------------- + +inline FractalGroup& TerrainGenerator::getFractalGroup () +{ + return m_fractalGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline const BitmapGroup& TerrainGenerator::getBitmapGroup () const +{ + return m_bitmapGroup; +} + +//------------------------------------------------------------------- + +inline BitmapGroup& TerrainGenerator::getBitmapGroup () +{ + return m_bitmapGroup; //lint !e1536 // exposing low access member +} + +//------------------------------------------------------------------- + +inline bool TerrainGenerator::LayerItem::isActive () const +{ + return m_active; +} + + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.cpp new file mode 100644 index 00000000..a104ea93 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.cpp @@ -0,0 +1,496 @@ +// +// TerrainGeneratorLoader.cpp +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainGeneratorLoader.h" + +#include "sharedFile/Iff.h" +#include "sharedTerrain/Affector.h" +#include "sharedTerrain/AffectorColor.h" +#include "sharedTerrain/AffectorEnvironment.h" +#include "sharedTerrain/AffectorFloraDynamic.h" +#include "sharedTerrain/AffectorFloraStatic.h" +#include "sharedTerrain/AffectorRibbon.h" +#include "sharedTerrain/AffectorHeight.h" +#include "sharedTerrain/AffectorPassable.h" +#include "sharedTerrain/AffectorRiver.h" +#include "sharedTerrain/AffectorRoad.h" +#include "sharedTerrain/AffectorShader.h" +#include "sharedTerrain/Boundary.h" +#include "sharedTerrain/Filter.h" + +//------------------------------------------------------------------- + +void TerrainGeneratorLoader::loadLayerItem (Iff& iff, TerrainGenerator* terrainGenerator, TerrainGenerator::Layer* layer) +{ + TerrainGenerator::Boundary* boundary = createBoundary (iff); + + if (boundary) + layer->addBoundary (boundary); + else + { + TerrainGenerator::Filter* filter = createFilter (iff, terrainGenerator); + + if (filter) + layer->addFilter (filter); + else + { + TerrainGenerator::Affector* affector = createAffector (iff, terrainGenerator); + + if (affector) + layer->addAffector (affector); + else + { + DEBUG_FATAL (iff.getCurrentName () != TAG_LAYR, ("not at layer in terrain file")); + + TerrainGenerator::Layer* sublayer = new TerrainGenerator::Layer (); + sublayer->load (iff, terrainGenerator); + layer->addLayer (sublayer); + } //lint !e429 //-- sublayer has not been freed or returned + } + } +} + +//------------------------------------------------------------------- + +TerrainGenerator::Boundary* TerrainGeneratorLoader::createBoundary (Iff& iff) +{ + TerrainGenerator::Boundary* boundary = 0; + + switch (iff.getCurrentName ()) + { + case TAG_BALL: + { + //-- this boundary is no longer used + iff.enterForm (TAG_BALL); + iff.exitForm (TAG_BALL, true); + } + break; + + case TAG_BCIR: + { + iff.enterForm (TAG_BCIR); + + boundary = new BoundaryCircle (); + boundary->load (iff); + + iff.exitForm (TAG_BCIR); + } + break; + + case TAG_BREC: + { + iff.enterForm (TAG_BREC); + + boundary = new BoundaryRectangle (); + boundary->load (iff); + + iff.exitForm (TAG_BREC); + } + break; + + case TAG_BPOL: + { + iff.enterForm (TAG_BPOL); + + boundary = new BoundaryPolygon (); + boundary->load (iff); + + iff.exitForm (TAG_BPOL); + } + break; + + case TAG_BSPL: + { + //-- this boundary is no longer used + iff.enterForm (TAG_BSPL); + iff.exitForm (TAG_BSPL, true); + } + break; + + case TAG_BPLN: + { + iff.enterForm (TAG_BPLN); + + boundary = new BoundaryPolyline (); + boundary->load (iff); + + iff.exitForm (TAG_BPLN); + } + break; + + default: + break; + } + + return boundary; +} + +//------------------------------------------------------------------- + +TerrainGenerator::Filter* TerrainGeneratorLoader::createFilter (Iff& iff, TerrainGenerator* terrainGenerator) +{ + TerrainGenerator::Filter* filter = 0; + + switch (iff.getCurrentName ()) + { + case TAG_FHGT: + { + iff.enterForm (TAG_FHGT); + + filter = new FilterHeight (); + filter->load (iff); + + iff.exitForm (TAG_FHGT); + } + break; + + case TAG_FFRA: + { + iff.enterForm (TAG_FFRA); + + FilterFractal* filterFractal = new FilterFractal (); + filterFractal->load (iff, terrainGenerator->getFractalGroup ()); + filter = filterFractal; + + iff.exitForm (TAG_FFRA); + } + break; + + case TAG_FBIT: + { + iff.enterForm (TAG_FBIT); + + FilterBitmap* filterBitmap = new FilterBitmap (); + filterBitmap->load (iff /*, terrainGenerator->getBitmapGroup ()*/); + filter = filterBitmap; + + iff.exitForm (TAG_FBIT); + } + break; + + case TAG_FSLP: + { + iff.enterForm (TAG_FSLP); + + filter = new FilterSlope (); + filter->load (iff); + + iff.exitForm (TAG_FSLP); + } + break; + + case TAG_FDIR: + { + iff.enterForm (TAG_FDIR); + + filter = new FilterDirection (); + filter->load (iff); + + iff.exitForm (TAG_FDIR); + } + break; + + case TAG_FSHD: + { + iff.enterForm (TAG_FSHD); + + filter = new FilterShader (); + filter->load (iff); + + iff.exitForm (TAG_FSHD); + } + break; + + default: + break; + } + + return filter; +} + +//------------------------------------------------------------------- + +TerrainGenerator::Affector* TerrainGeneratorLoader::createAffector (Iff& iff, TerrainGenerator* terrainGenerator) +{ + TerrainGenerator::Affector* affector = 0; + + switch (iff.getCurrentName ()) + { + case TAG_AHSM: + { + //-- AffectorHeightSmoother no longer exists + iff.enterForm (TAG_AHSM); + iff.exitForm (TAG_AHSM, true); + } + break; + + case TAG_AHBM: + { + //-- AffectorHeightBitmap no longer exists + iff.enterForm (TAG_AHBM); + iff.exitForm (TAG_AHBM, true); + } + break; + + case TAG_ACBM: + { + //-- AffectorColorBitmap no longer exists + iff.enterForm (TAG_ACBM); + iff.exitForm (TAG_ACBM, true); + } + break; + + case TAG_ASBM: + { + //-- AffectorShaderBitmap no longer exists + iff.enterForm (TAG_ASBM); + iff.exitForm (TAG_ASBM, true); + } + break; + + case TAG_AFBM: + { + //-- AffectorFloraBitmap no longer exists + iff.enterForm (TAG_AFBM); + iff.exitForm (TAG_AFBM, true); + } + break; + + case TAG_AENV: + { + iff.enterForm (TAG_AENV); + + affector = new AffectorEnvironment (); + affector->load (iff); + + iff.exitForm (TAG_AENV); + } + break; + + case TAG_AHTR: + { + iff.enterForm (TAG_AHTR); + + affector = new AffectorHeightTerrace (); + affector->load (iff); + + iff.exitForm (TAG_AHTR); + } + break; + + case TAG_AHCN: + { + iff.enterForm (TAG_AHCN); + + affector = new AffectorHeightConstant (); + affector->load (iff); + + iff.exitForm (TAG_AHCN); + } + break; + + case TAG_AHFR: + { + iff.enterForm (TAG_AHFR); + + AffectorHeightFractal* affectorHeightFractal = new AffectorHeightFractal (); + affectorHeightFractal->load (iff, terrainGenerator->getFractalGroup ()); + affector = affectorHeightFractal; + + iff.exitForm (TAG_AHFR); + } + break; + + case TAG_ACCN: + { + iff.enterForm (TAG_ACCN); + + affector = new AffectorColorConstant (); + affector->load (iff); + + iff.exitForm (TAG_ACCN); + } + break; + + case TAG_ACRH: + { + iff.enterForm (TAG_ACRH); + + affector = new AffectorColorRampHeight (); + affector->load (iff); + + iff.exitForm (TAG_ACRH); + } + break; + + case TAG_ACRF: + { + iff.enterForm (TAG_ACRF); + + AffectorColorRampFractal* affectorColorRampFractal = new AffectorColorRampFractal (); + affectorColorRampFractal->load (iff, terrainGenerator->getFractalGroup ()); + affector = affectorColorRampFractal; + + iff.exitForm (TAG_ACRF); + } + break; + + case TAG_ASCN: + { + iff.enterForm (TAG_ASCN); + + affector = new AffectorShaderConstant (); + affector->load (iff); + + iff.exitForm (TAG_ASCN); + } + break; + + case TAG_ASRP: + { + iff.enterForm (TAG_ASRP); + + affector = new AffectorShaderReplace (); + affector->load (iff); + + iff.exitForm (TAG_ASRP); + } + break; + + case TAG_AFCN: + { + iff.enterForm (TAG_AFCN); + + affector = new AffectorFloraStaticCollidableConstant (); + affector->load (iff); + + iff.exitForm (TAG_AFCN); + } + break; + + case TAG_AFSC: + { + iff.enterForm (TAG_AFSC); + + affector = new AffectorFloraStaticCollidableConstant (); + affector->load (iff); + + iff.exitForm (TAG_AFSC); + } + break; + + case TAG_AFSN: + { + iff.enterForm (TAG_AFSN); + + affector = new AffectorFloraStaticNonCollidableConstant (); + affector->load (iff); + + iff.exitForm (TAG_AFSN); + } + break; + + case TAG_ARCN: + { + iff.enterForm (TAG_ARCN); + + affector = new AffectorFloraDynamicNearConstant (); + affector->load (iff); + + iff.exitForm (TAG_ARCN); + } + break; + + case TAG_AFDN: + { + iff.enterForm (TAG_AFDN); + + affector = new AffectorFloraDynamicNearConstant (); + affector->load (iff); + + iff.exitForm (TAG_AFDN); + } + break; + + case TAG_AFDF: + { + iff.enterForm (TAG_AFDF); + + affector = new AffectorFloraDynamicFarConstant (); + affector->load (iff); + + iff.exitForm (TAG_AFDF); + } + break; + + case TAG_ARIB: + { + iff.enterForm (TAG_ARIB); + + affector = new AffectorRibbon (); + affector->load (iff); + + iff.exitForm (TAG_ARIB); + } + break; + + case TAG_AEXC: + { + iff.enterForm (TAG_AEXC); + + affector = new AffectorExclude (); + affector->load (iff); + + iff.exitForm (TAG_AEXC); + } + break; + + case TAG_APAS: + { + iff.enterForm (TAG_APAS); + + affector = new AffectorPassable(); + affector->load (iff); + + iff.exitForm (TAG_APAS); + } + break; + + case TAG_AROA: + { + iff.enterForm (TAG_AROA); + + affector = new AffectorRoad (); + affector->load (iff); + + iff.exitForm (TAG_AROA); + } + break; + + case TAG_ARIV: + { + iff.enterForm (TAG_ARIV); + + affector = new AffectorRiver (); + affector->load (iff); + + iff.exitForm (TAG_ARIV); + } + break; + + default: + break; + } + + return affector; +} + +//------------------------------------------------------------------- + diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.h b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.h new file mode 100644 index 00000000..e4b00c9d --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorLoader.h @@ -0,0 +1,50 @@ +//=================================================================== +// +// TerrainGeneratorLoader.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//-- +// +// this class knows about all of the available terrain generator Layers, +// Actions, Boundaries, Filters and Affectors and how to initialize them +// +//=================================================================== + +#ifndef INCLUDED_TerrainGeneratorLoader_H +#define INCLUDED_TerrainGeneratorLoader_H + +//=================================================================== + +#include "sharedTerrain/TerrainGenerator.h" + +//=================================================================== + +class TerrainGeneratorLoader +{ +private: + + TerrainGeneratorLoader (); + ~TerrainGeneratorLoader (); + TerrainGeneratorLoader (const TerrainGeneratorLoader& rhs); + TerrainGeneratorLoader& operator= (const TerrainGeneratorLoader& rhs); + +public: + + //-- createLayer instantiates a layer + static void loadLayerItem (Iff& iff, TerrainGenerator* terrainGenerator, TerrainGenerator::Layer* layer); + + //-- createBoundary instantiates a boundary + static TerrainGenerator::Boundary* createBoundary (Iff& iff); + + //-- createFilter instantiates a filter + static TerrainGenerator::Filter* createFilter (Iff& iff, TerrainGenerator* terrainGenerator); + + //-- createAffector instantiates a affector + static TerrainGenerator::Affector* createAffector (Iff& iff, TerrainGenerator* terrainGenerator); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.def b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.def new file mode 100644 index 00000000..1d25829c --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.def @@ -0,0 +1,118 @@ +// +// TerrainGeneratorType.def +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// + +//------------------------------------------------------------------- + +#ifndef TERRAINGENERATORTYPE_DEF +#define TERRAINGENERATORTYPE_DEF + +//------------------------------------------------------------------- + +enum TerrainGeneratorMap +{ + TGM_height = (1<< 0), + TGM_color = (1<< 1), + TGM_shader = (1<< 2), + TGM_floraStaticCollidable = (1<< 3), + TGM_floraStaticNonCollidable = (1<< 4), + TGM_floraDynamicNear = (1<< 5), + TGM_floraDynamicFar = (1<< 6), + TGM_environment = (1<< 7), + TGM_vertexPosition = (1<< 8), + TGM_vertexNormal = (1<< 9), + TGM_exclude = (1<<10), + TGM_passable = (1<<11), + + TGM_ALL = 0xffffffff +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorBoundaryType +{ + TGBT_circle, + TGBT_rectangle, + TGBT_polygon, + TGBT_polyline +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorFilterType +{ + TGFT_height, + TGFT_fractal, + TGFT_slope, + TGFT_direction, + TGFT_shader, + TGFT_bitmap +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorAffectorType +{ + TGAT_heightTerrace, + TGAT_heightConstant, + TGAT_heightFractal, + TGAT_colorConstant, + TGAT_colorRampHeight, + TGAT_colorRampFractal, + TGAT_shaderConstant, + TGAT_shaderReplace, + TGAT_floraStaticCollidableConstant, + TGAT_floraStaticNonCollidableConstant, + TGAT_floraDynamicNearConstant, + TGAT_floraDynamicFarConstant, + TGAT_exclude, + TGAT_passable, + TGAT_road, + TGAT_river, + TGAT_environment, + TGAT_ribbon, + + TGAT_COUNT +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorOperation +{ + TGO_replace, + TGO_add, + TGO_subtract, + TGO_multiply, + + TGO_COUNT +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorFeatherFunction +{ + TGFF_linear, + TGFF_easeIn, + TGFF_easeOut, + TGFF_easeInOut, + + TGFF_COUNT +}; + +//------------------------------------------------------------------- + +enum TerrainGeneratorWaterType +{ + TGWT_invalid = -1, + TGWT_water, + TGWT_lava, + + TGWT_COUNT +}; + +//------------------------------------------------------------------- + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.h b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.h new file mode 100644 index 00000000..b71bc9bb --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainGeneratorType.h @@ -0,0 +1,72 @@ +//=================================================================== +// +// TerrainGeneratorType.h +// asommers 9-11-2000 +// +// copyright 2000, verant interactive +// +//=================================================================== + +#ifndef INCLUDED_TerrainGeneratorType_H +#define INCLUDED_TerrainGeneratorType_H + +//=================================================================== + +#include "sharedTerrain/TerrainGeneratorType.def" + +//=================================================================== + +//-- boundaries +const Tag TAG_BALL = TAG (B,A,L,L); +const Tag TAG_BCIR = TAG (B,C,I,R); +const Tag TAG_BPLN = TAG (B,P,L,N); +const Tag TAG_BPOL = TAG (B,P,O,L); +const Tag TAG_BREC = TAG (B,R,E,C); +const Tag TAG_BSPL = TAG (B,S,P,L); + +//-- filters +const Tag TAG_FBIT = TAG (F,B,I,T); // bitmap +const Tag TAG_FDIR = TAG (F,D,I,R); // direction +const Tag TAG_FFRA = TAG (F,F,R,A); // fractal +const Tag TAG_FHGT = TAG (F,H,G,T); // height +const Tag TAG_FSHD = TAG (F,S,H,D); // shader +const Tag TAG_FSLP = TAG (F,S,L,P); // slope + +//-- affectors +const Tag TAG_ACBM = TAG (A,C,B,M); +const Tag TAG_ACCN = TAG (A,C,C,N); +const Tag TAG_ACRF = TAG (A,C,R,F); +const Tag TAG_ACRH = TAG (A,C,R,H); +const Tag TAG_AEXC = TAG (A,E,X,C); +const Tag TAG_APAS = TAG (A,P,A,S); +const Tag TAG_AENV = TAG (A,E,N,V); +const Tag TAG_AFBM = TAG (A,F,B,M); +const Tag TAG_AFCN = TAG (A,F,C,N); +const Tag TAG_AFDF = TAG (A,F,D,F); +const Tag TAG_AFDN = TAG (A,F,D,N); +const Tag TAG_AFSC = TAG (A,F,S,C); +const Tag TAG_AFSN = TAG (A,F,S,N); +const Tag TAG_AHBM = TAG (A,H,B,M); +const Tag TAG_AHCN = TAG (A,H,C,N); +const Tag TAG_AHFR = TAG (A,H,F,R); +const Tag TAG_AHSM = TAG (A,H,S,M); +const Tag TAG_AHTR = TAG (A,H,T,R); +const Tag TAG_ARCN = TAG (A,R,C,N); +const Tag TAG_ARIB = TAG (A,R,I,B); +const Tag TAG_ARIV = TAG (A,R,I,V); +const Tag TAG_AROA = TAG (A,R,O,A); +const Tag TAG_ASBM = TAG (A,S,B,M); +const Tag TAG_ASCN = TAG (A,S,C,N); +const Tag TAG_ASRP = TAG (A,S,R,P); + +//-- misc +const Tag TAG_TGEN = TAG (T,G,E,N); +const Tag TAG_LYRS = TAG (L,Y,R,S); +const Tag TAG_IHDR = TAG (I,H,D,R); +const Tag TAG_LAYR = TAG (L,A,Y,R); +const Tag TAG_ACTN = TAG (A,C,T,N); +const Tag TAG_ADTA = TAG (A,D,T,A); + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.cpp b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.cpp new file mode 100644 index 00000000..2789980d --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.cpp @@ -0,0 +1,110 @@ +//=================================================================== +// +// TerrainModificationHelper.cpp +// copyright 2001, sony online entertainment +// +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainModificationHelper.h" + +#include "sharedTerrain/AffectorHeight.h" +#include "sharedFile/Iff.h" + +//=================================================================== + +void TerrainModificationHelper::setHeight (TerrainGenerator::Layer* layer, float height) +{ + layer->setModificationHeight (height); + + { + int i; + for (i = 0; i < layer->getNumberOfAffectors (); ++i) + if (layer->getAffector (i)->isActive () && layer->getAffector (i)->getType () == TGAT_heightConstant) + safe_cast (layer->getAffector (i))->setHeight (height); + } + + { + int i; + for (i = 0; i < layer->getNumberOfLayers (); ++i) + if (layer->getLayer (i)->isActive ()) + setHeight (layer->getLayer (i), height); + } +} + +//------------------------------------------------------------------- + +void TerrainModificationHelper::setPosition (TerrainGenerator::Layer* layer, const Vector2d& position) +{ + { + int i; + for (i = 0; i < layer->getNumberOfBoundaries (); ++i) + if (layer->getBoundary (i)->isActive ()) + layer->getBoundary (i)->setCenter (position); + } + + { + int i; + for (i = 0; i < layer->getNumberOfLayers (); i++) + if (layer->getLayer (i)->isActive ()) + setPosition (layer->getLayer (i), position); + } +} + +//------------------------------------------------------------------- + +void TerrainModificationHelper::setRotation (TerrainGenerator::Layer* layer, float angle) +{ + { + int i; + for (i = 0; i < layer->getNumberOfBoundaries (); ++i) + if (layer->getBoundary (i)->isActive ()) + layer->getBoundary (i)->setRotation (angle); + } + + { + int i; + for (i = 0; i < layer->getNumberOfLayers (); i++) + if (layer->getLayer (i)->isActive ()) + setRotation (layer->getLayer (i), angle); + } +} + +//------------------------------------------------------------------- + +TerrainGenerator::Layer* TerrainModificationHelper::importLayer (const char* filename) +{ + Iff iff; + if (iff.open (filename, true)) + { + ShaderGroup* shaderGroup = new ShaderGroup; + shaderGroup->load (iff); + delete shaderGroup; + + FloraGroup* floraGroup = new FloraGroup; + floraGroup->load (iff); + delete floraGroup; + + RadialGroup* radialGroup = new RadialGroup; + radialGroup->load (iff); + delete radialGroup; + + EnvironmentGroup* environmentGroup = new EnvironmentGroup; + environmentGroup->load (iff); + delete environmentGroup; + + FractalGroup* fractalGroup = new FractalGroup; + fractalGroup->load (iff); + delete fractalGroup; + + TerrainGenerator::Layer* const newLayer = new TerrainGenerator::Layer; + newLayer->load (iff, 0); + + return newLayer; + } + + return 0; +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.h b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.h new file mode 100644 index 00000000..64ef5995 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/generator/TerrainModificationHelper.h @@ -0,0 +1,37 @@ +//=================================================================== +// +// TerrainModificationHelper.h +// copyright 2001, sony online entertainment +// +// +//=================================================================== + +#ifndef INCLUDED_TerrainModificationHelper_H +#define INCLUDED_TerrainModificationHelper_H + +//=================================================================== + +#include "TerrainGenerator.h" + +//=================================================================== + +class TerrainModificationHelper +{ +public: + + static void setPosition (TerrainGenerator::Layer* layer, const Vector2d& position); + static void setRotation (TerrainGenerator::Layer* layer, float angle); + static void setHeight (TerrainGenerator::Layer* layer, float height); + static TerrainGenerator::Layer* importLayer (const char* filename); + +private: + + TerrainModificationHelper (); + ~TerrainModificationHelper (); + TerrainModificationHelper (const TerrainModificationHelper& rhs); + TerrainModificationHelper& operator= (const TerrainModificationHelper& rhs); +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.cpp b/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.cpp new file mode 100644 index 00000000..30f74727 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.cpp @@ -0,0 +1,795 @@ +//=================================================================== +// +// TerrainObject.cpp +// asommers 3-1-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainObject.h" + +#include "sharedCollision/CollideParameters.h" +#include "sharedCollision/CollisionInfo.h" +#include "sharedDebug/DebugFlags.h" +#include "sharedFoundation/ExitChain.h" +#include "sharedMath/Sphere.h" +#include "sharedTerrain/ConfigSharedTerrain.h" +#include "sharedTerrain/TerrainAppearance.h" + +#include +#include + +//=================================================================== + +namespace +{ + inline const TerrainAppearance* getCastedAppearance (const Object* const object) + { + NOT_NULL (object); + return safe_cast (object->getAppearance ()); + } + + inline TerrainAppearance* getCastedAppearance (Object* const object) + { + NOT_NULL (object); + return safe_cast (object->getAppearance ()); + } + + const Vector2d ms_invalidPosition_w (FLT_MAX, FLT_MAX); + bool ms_debugReport; + + typedef std::vector TerrainChangedFunctionList; + TerrainChangedFunctionList ms_terrainChangedFunctionList; +} + +//=================================================================== +// STATIC PUBLIC TerrainObject +//=================================================================== + +TerrainObject* TerrainObject::ms_instance; +bool TerrainObject::ms_useCache = true; + +//=================================================================== + +void TerrainObject::install () +{ + DebugFlags::registerFlag (ms_debugReport, "SharedTerrain", "debugReport", debugDump); + + ExitChain::add (remove, "TerrainObject::remove"); +} + +//------------------------------------------------------------------- + +void TerrainObject::remove () +{ + DebugFlags::unregisterFlag (ms_debugReport); +} + +//------------------------------------------------------------------- + +TerrainObject* TerrainObject::getInstance () +{ + return ms_instance; +} + +//------------------------------------------------------------------- + +const TerrainObject* TerrainObject::getConstInstance () +{ + return ms_instance; +} + +//------------------------------------------------------------------- + +void TerrainObject::setUseCache (bool useCache) +{ + ms_useCache = useCache; +} + +//------------------------------------------------------------------- + +void TerrainObject::addTerrainChangedFunction (TerrainObject::TerrainChangedFunction terrainChangedFunction) +{ + ms_terrainChangedFunctionList.push_back (terrainChangedFunction); +} + +//------------------------------------------------------------------- + +void TerrainObject::terrainChanged (Rectangle2d const & extent2d) +{ + TerrainChangedFunctionList::iterator end = ms_terrainChangedFunctionList.end (); + for (TerrainChangedFunctionList::iterator iter = ms_terrainChangedFunctionList.begin (); iter != end; ++iter) + (*iter) (extent2d); +} + +//------------------------------------------------------------------- + +void TerrainObject::debugDump () +{ + if (ms_instance) + getCastedAppearance (ms_instance)->debugDump (); +} + +//=================================================================== +// PUBLIC TerrainObject +//=================================================================== + +TerrainObject::TerrainObject () : + Object (), + m_cachedPosition_w (ms_invalidPosition_w), + m_cachedPositionHeight (0.f), + m_cachedPositionNormal_w (ms_invalidPosition_w), + m_cachedPositionNormalHeight (0.f), + m_cachedPositionNormalNormal_w (Vector::unitY), + m_cachedPositionWater_w (ms_invalidPosition_w), + m_cachedPositionWaterHeight (0.f), + m_cachedPositionWaterType(TGWT_invalid) +{ + DEBUG_FATAL (ms_instance, ("TerrainObject instance already exists")); + ms_instance = this; +} + +//------------------------------------------------------------------- + +TerrainObject::TerrainObject (const ObjectNotification ¬ification) : + Object (), + m_cachedPosition_w (ms_invalidPosition_w), + m_cachedPositionHeight (0.f), + m_cachedPositionNormal_w (ms_invalidPosition_w), + m_cachedPositionNormalHeight (0.f), + m_cachedPositionNormalNormal_w (Vector::unitY), + m_cachedPositionWater_w (ms_invalidPosition_w), + m_cachedPositionWaterHeight (0.f), + m_cachedPositionWaterType(TGWT_invalid) +{ + DEBUG_FATAL (ms_instance, ("TerrainObject instance already exists")); + ms_instance = this; + addNotification (notification); +} + +//------------------------------------------------------------------- + +TerrainObject::~TerrainObject () +{ + //remove from world + if (isInWorld ()) + TerrainObject::removeFromWorld (); + + DEBUG_FATAL (ms_instance != this, ("TerrainObject instance is not this object")); + ms_instance = NULL; +} + +//------------------------------------------------------------------- + +bool TerrainObject::placeObject (Object& object, bool alignToTerrain, bool forceChunkCreation) const +{ + // @todo ALS handle align to terrain + UNREF (alignToTerrain); + + //-- make sure the object is both in the world and in the world cell + if (!object.isInWorld () || !object.isInWorldCell ()) + { + DEBUG_WARNING (true, ("TerrainObject::placeObject - object is not in world or not in world cell (id=%s, template=%s)", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName ())); + return false; + } + + const Vector& position_w = object.getPosition_w (); + + float height; + + if (forceChunkCreation) + { + if (getHeightForceChunkCreation (position_w, height)) + { + object.setPosition_w (Vector (position_w.x, height, position_w.z)); + return true; + } + } + else + { + if (getHeight (position_w, height)) + { + object.setPosition_w (Vector (position_w.x, height, position_w.z)); + return true; + } + } + + DEBUG_WARNING (true, ("TerrainObject::placeObject (id=%s, template=%s) failed for %s location <%1.2f, %1.2f>", object.getNetworkId ().getValueString ().c_str (), object.getObjectTemplateName (), forceChunkCreation ? "forced" : "non-forced", position_w.x, position_w.z)); + return false; +} + +//------------------------------------------------------------------- + +bool TerrainObject::getLogicalHeight (const Vector& position_w, const float swimHeight, float& logicalHeight, float& realHeight) const +{ + if (getHeight (position_w, realHeight)) + { + float waterHeight; + if (getWaterHeight (position_w, waterHeight) && (waterHeight - swimHeight > realHeight)) + logicalHeight = waterHeight - swimHeight; + else + logicalHeight = realHeight; + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +bool TerrainObject::getLogicalHeight (const Vector& position_w, const float swimHeight, float& logicalHeight, float& realHeight, Vector& normal) const +{ + if (getHeight (position_w, realHeight, normal)) + { + float waterHeight; + if (getWaterHeight (position_w, waterHeight) && (waterHeight - swimHeight > realHeight)) + logicalHeight = waterHeight - swimHeight; + else + logicalHeight = realHeight; + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +bool TerrainObject::getHeight (const Vector& position_w, float& height) const +{ + const Vector2d position (position_w.x, position_w.z); + + if (ms_useCache && position == m_cachedPosition_w) + { + height = m_cachedPositionHeight; + + return true; + } + + const bool result = getCastedAppearance (this)->getHeight (rotateTranslate_w2o (position_w), height); + + if (result) + { + m_cachedPosition_w = position; + m_cachedPositionHeight = height; + } + else + m_cachedPosition_w = ms_invalidPosition_w; + + return result; +} + +//------------------------------------------------------------------- + +bool TerrainObject::getHeight (const Vector& position_w, float& height, Vector& normal) const +{ + const Vector2d position (position_w.x, position_w.z); + + if (ms_useCache && position == m_cachedPositionNormal_w) + { + height = m_cachedPositionNormalHeight; + normal = m_cachedPositionNormalNormal_w; + + return true; + } + + const bool result = getCastedAppearance (this)->getHeight (rotateTranslate_w2o (position_w), height, normal); + + if (result) + { + normal = rotate_o2w (normal); + + m_cachedPositionNormal_w = position; + m_cachedPositionNormalHeight = height; + m_cachedPositionNormalNormal_w = normal; + } + else + m_cachedPositionNormal_w = ms_invalidPosition_w; + + return result; +} + +//------------------------------------------------------------------- + +bool TerrainObject::getHeightForceChunkCreation (const Vector& position_w, float& height) const +{ + return getCastedAppearance (this)->getHeightForceChunkCreation (rotateTranslate_w2o (position_w), height); +} + +//------------------------------------------------------------------- + +const ObjectTemplate* TerrainObject::getSurfaceProperties (const Vector& position_w) const +{ + return getCastedAppearance (this)->getSurfaceProperties (rotateTranslate_w2o (position_w)); +} + +//------------------------------------------------------------------- + +int TerrainObject::getTerrainType (const Vector &position_w) const +{ + return getCastedAppearance (this)->getTerrainType (rotateTranslate_w2o (position_w)); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getWaterHeight (const Vector& position_w, float& height) const +{ + TerrainGeneratorWaterType waterType; + return getWaterHeight(position_w,height,waterType); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getWaterHeight (const Vector& position_w, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater) const +{ + const Vector2d position (position_w.x, position_w.z); + + if (ms_useCache && position == m_cachedPositionWater_w) + { + height = m_cachedPositionWaterHeight; + waterType = m_cachedPositionWaterType; + return true; + } + + const bool result = getCastedAppearance (this)->getWaterHeight (rotateTranslate_w2o (position_w), height, waterType, ignoreNonTransparentWater); + + if (result) + { + m_cachedPositionWater_w = position; + m_cachedPositionWaterHeight = height; + m_cachedPositionWaterType = waterType; + } + else + m_cachedPositionWater_w = ms_invalidPosition_w; + + return result; +} + +//------------------------------------------------------------------- + +TerrainGeneratorWaterType TerrainObject::getWaterType (const Vector& position_w) const +{ + const TerrainGeneratorWaterType ret = getCastedAppearance (this)->getWaterType (rotateTranslate_w2o (position_w)); + return ret; +} + +//------------------------------------------------------------------- + +bool TerrainObject::isBelowWater (const Vector& position_w) const +{ + float waterHeight; + return getWaterHeight (position_w, waterHeight) && (position_w.y < waterHeight); +} + +//------------------------------------------------------------------- + +bool TerrainObject::isBelowWater (const Vector& position_w, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater) const +{ + float waterHeight; + return getWaterHeight (position_w, waterHeight, waterType, ignoreNonTransparentWater) && (position_w.y < waterHeight); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getWater (const Rectangle2d& rectangle) const +{ + return getCastedAppearance (this)->getWater (rectangle); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getSlope (const Rectangle2d& rectangle) const +{ + return getCastedAppearance (this)->getSlope (rectangle); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getWater (const int chunkX, const int chunkZ) const +{ + return getCastedAppearance (this)->getWater (chunkX, chunkZ); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getSlope (const int chunkX, const int chunkZ) const +{ + return getCastedAppearance (this)->getSlope (chunkX, chunkZ); +} + +//------------------------------------------------------------------- + +float TerrainObject::getChunkWidthInMeters () const +{ + return getCastedAppearance (this)->getChunkWidthInMeters (); +} + +//------------------------------------------------------------------- + +float TerrainObject::getMapWidthInMeters () const +{ + return getCastedAppearance (this)->getMapWidthInMeters (); +} + +//------------------------------------------------------------------- + +float TerrainObject::getMaximumValidHeightInMeters () const +{ + return ConfigSharedTerrain::getMaximumValidHeightInMeters (); +} + +//------------------------------------------------------------------- + +int TerrainObject::getNumberOfChunks () const +{ + return getCastedAppearance (this)->getNumberOfChunks (); +} + +//------------------------------------------------------------------- + +bool TerrainObject::hasHighLevelOfDetailTerrain (const Vector& position_w) const +{ + return getCastedAppearance (this)->hasHighLevelOfDetailTerrain (rotateTranslate_w2o (position_w)); +} + +//------------------------------------------------------------------- + +int TerrainObject::calculateChunkX (const Vector& position_w) const +{ + return getCastedAppearance (this)->calculateChunkX (rotateTranslate_w2o (position_w).x); +} + +//------------------------------------------------------------------- + +int TerrainObject::calculateChunkZ (const Vector& position_w) const +{ + return getCastedAppearance (this)->calculateChunkZ (rotateTranslate_w2o (position_w).z); +} + +//------------------------------------------------------------------- + +float TerrainObject::getChunkHeight (const int chunkX, const int chunkZ) const +{ + return getCastedAppearance (this)->getChunkHeight (chunkX, chunkZ); +} + +//------------------------------------------------------------------- + +const BoxExtent* TerrainObject::getChunkExtent (const Vector& position_w) const +{ + return getCastedAppearance (this)->getChunkExtent (rotateTranslate_w2o (position_w)); +} + +//------------------------------------------------------------------- + +const BoxExtent* TerrainObject::getChunkExtentForceChunkCreation (const Vector& position_w) const +{ + return getCastedAppearance (this)->getChunkExtentForceChunkCreation (rotateTranslate_w2o (position_w)); +} + +//------------------------------------------------------------------- + +bool TerrainObject::collide (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const +{ + if (getCastedAppearance(this)->collide(rotateTranslate_w2o(start_w), rotateTranslate_w2o(end_w), CollideParameters::cms_default, result)) + { + result.setObject (this); + result.setPoint (rotateTranslate_o2w (result.getPoint ())); + result.setNormal (rotate_o2w (result.getNormal ())); + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +bool TerrainObject::collideForceChunkCreation (Vector const & start_w, Vector const & end_w, CollisionInfo & result) +{ + return getCastedAppearance(this)->collideForceChunkCreation(rotateTranslate_w2o(start_w), rotateTranslate_w2o(end_w), result); +} + +//------------------------------------------------------------------- + +bool TerrainObject::collideObjects (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const +{ + if (getCastedAppearance (this)->collideObjects (rotateTranslate_w2o (start_w), rotateTranslate_w2o (end_w), result)) + { + result.setPoint (rotateTranslate_o2w (result.getPoint ())); + result.setNormal (rotate_o2w (result.getNormal ())); + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +bool TerrainObject::approximateCollideObjects (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const +{ + if (getCastedAppearance (this)->approximateCollideObjects (rotateTranslate_w2o (start_w), rotateTranslate_w2o (end_w), result)) + { + result.setPoint (rotateTranslate_o2w (result.getPoint ())); + result.setNormal (rotate_o2w (result.getNormal ())); + + return true; + } + + return false; +} + +//------------------------------------------------------------------- + +void TerrainObject::preRender (const Camera* const camera) const +{ + getCastedAppearance (this)->preRender (camera); +} + +//------------------------------------------------------------------- + +void TerrainObject::postRender () const +{ + getCastedAppearance (this)->postRender (); +} + +//------------------------------------------------------------------- + +void TerrainObject::addReferenceObject (const Object* const referenceObject) +{ + getCastedAppearance (this)->addReferenceObject (referenceObject); +} + +//------------------------------------------------------------------- + +int TerrainObject::getNumberOfReferenceObjects() const +{ + return getCastedAppearance (this)->getNumberOfReferenceObjects(); +} + +//------------------------------------------------------------------- + +void TerrainObject::removeReferenceObject (const Object* const referenceObject) +{ + getCastedAppearance (this)->removeReferenceObject (referenceObject); +} + +//------------------------------------------------------------------- + +void TerrainObject::removeAllReferenceObjects () +{ + getCastedAppearance (this)->removeAllReferenceObjects (); +} + +//------------------------------------------------------------------- + +bool TerrainObject::isReferenceObject (const Object* const referenceObject) const +{ + return getCastedAppearance (this)->isReferenceObject (referenceObject); +} + +//------------------------------------------------------------------- + +bool TerrainObject::getPauseEnvironment () const +{ + return getCastedAppearance (this)->getPauseEnvironment (); +} + +//------------------------------------------------------------------- + +void TerrainObject::setPauseEnvironment (bool const pauseEnvironment) +{ + getCastedAppearance (this)->setPauseEnvironment (pauseEnvironment); +} + +//------------------------------------------------------------------- + +float TerrainObject::getEnvironmentCycleTime () const +{ + return getCastedAppearance (this)->getEnvironmentCycleTime (); +} + +//------------------------------------------------------------------- + +const PackedRgb TerrainObject::getClearColor () const +{ + return getCastedAppearance (this)->getClearColor (); +} + +//------------------------------------------------------------------- + +const PackedRgb TerrainObject::getFogColor () const +{ + return getCastedAppearance (this)->getFogColor (); +} + +//------------------------------------------------------------------- + +float TerrainObject::getFogDensity () const +{ + return getCastedAppearance (this)->getFogDensity (); +} + +//------------------------------------------------------------------- + +void TerrainObject::getTime (int& hour, int& minute) const +{ + getCastedAppearance (this)->getTime (hour, minute); +} + +//------------------------------------------------------------------- + +float TerrainObject::getTime () const +{ + return getCastedAppearance (this)->getTime (); +} + +//------------------------------------------------------------------- + +void TerrainObject::setTime (const float time, const bool force) +{ + getCastedAppearance (this)->setTime (time, force); +} + +//------------------------------------------------------------------- + +bool TerrainObject::isDay () const +{ + return getCastedAppearance (this)->isDay (); +} + +//---------------------------------------------------------------------- + +bool TerrainObject::isTimeLocked() const +{ + return getCastedAppearance(this)->isTimeLocked(); +} + +//------------------------------------------------------------------- + +void TerrainObject::addClearCollidableFloraObject (const Object* const object, const Vector& position_w, const float radius) +{ + getCastedAppearance (this)->addClearCollidableFloraObject (object, position_w, radius); +} + +//------------------------------------------------------------------- + +void TerrainObject::removeClearCollidableFloraObject (const Object* const object) +{ + getCastedAppearance (this)->removeClearCollidableFloraObject (object); +} + +//------------------------------------------------------------------- + +void TerrainObject::addClearNonCollidableFloraObject (const Object* const object, const ClearFloraEntryList& clearFloraEntryList) +{ + getCastedAppearance (this)->addClearNonCollidableFloraObject (object, clearFloraEntryList); +} + +//------------------------------------------------------------------- + +void TerrainObject::removeClearNonCollidableFloraObject (const Object* const object) +{ + getCastedAppearance (this)->removeClearNonCollidableFloraObject (object); +} + +//------------------------------------------------------------------- + +float TerrainObject::getHighLevelOfDetailThreshold () +{ + TerrainObject * const to = getInstance (); + if (to) + return getCastedAppearance (to)->getHighLevelOfDetailThreshold (); + + return 0.0f; +} + +//------------------------------------------------------------------- + +void TerrainObject::setHighLevelOfDetailThreshold (const float highLevelOfDetailThreshold) +{ + TerrainObject * const to = getInstance (); + if (to) + getCastedAppearance (to)->setHighLevelOfDetailThreshold (highLevelOfDetailThreshold); +} + +//------------------------------------------------------------------- + +float TerrainObject::getLevelOfDetailThreshold () +{ + TerrainObject * const to = getInstance (); + if (to) + return getCastedAppearance (to)->getLevelOfDetailThreshold (); + + return 1.0f; +} + +//------------------------------------------------------------------- + +void TerrainObject::setLevelOfDetailThreshold (const float levelOfDetailThreshold) +{ + TerrainObject * const to = getInstance (); + if (to) + getCastedAppearance (to)->setLevelOfDetailThreshold (levelOfDetailThreshold); +} + +//------------------------------------------------------------------- + +void TerrainObject::drawExtents (const Vector& position_w) const +{ + getCastedAppearance (this)->drawExtents (rotateTranslate_w2o (position_w)); +} + +// ---------------------------------------------------------------------- +/** + * Test whether a world x,z position falls within the boundaries of + * the terrain map. + * + * @param position_w a world-space position to test. + * + * @return true if the given position falls within the boundaries + * of the terrain map; false otherwise. + */ + +bool TerrainObject::isWithinTerrainBoundaries (Vector const &position_w) const +{ + //-- check x and z + float const maxCoordinate = getMapWidthInMeters () * 0.5f; + if ((abs (position_w.x) > maxCoordinate) || (abs (position_w.z) > maxCoordinate)) + return false; + + //-- check y + if (abs (position_w.y) > getMaximumValidHeightInMeters ()) + return false; + + return true; +} + +//---------------------------------------------------------------------- + +bool TerrainObject::isPassable(Vector const & position_w) const +{ + return getCastedAppearance(this)->isPassable(position_w); +} + +//---------------------------------------------------------------------- + +bool TerrainObject::isPassableForceChunkCreation(Vector const & position_w) const +{ + return getCastedAppearance(this)->isPassableForceChunkCreation(position_w); +} + +//------------------------------------------------------------------- + +void TerrainObject::getPolygonSoup (const Rectangle2d& extent2d_w, IndexedTriangleList& indexedTriangleList) const +{ + getCastedAppearance (this)->getPolygonSoup (extent2d_w, indexedTriangleList); +} + +//------------------------------------------------------------------- + +void TerrainObject::invalidateRegion (const Rectangle2d& extent2d) +{ + getCastedAppearance (this)->invalidateRegion (extent2d); +} + +//------------------------------------------------------------------- + +void TerrainObject::purgeChunks() +{ + getCastedAppearance(this)->purgeChunks(); +} + +//---------------------------------------------------------------------- + +bool TerrainObject::hasPassableAffectors() const +{ + return getCastedAppearance(this)->hasPassableAffectors(); +} + +//=================================================================== diff --git a/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.h b/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.h new file mode 100644 index 00000000..c396d252 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/object/TerrainObject.h @@ -0,0 +1,165 @@ +//=================================================================== +// +// TerrainObject.h +// asommers 3-1-99 +// +// copyright 1999, bootprint entertainment +// copyright 2001, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_TerrainObject_H +#define INCLUDED_TerrainObject_H + +//=================================================================== + +#include "sharedMath/PackedRgb.h" +#include "sharedMath/Vector2d.h" +#include "sharedObject/Object.h" +#include "sharedTerrain/TerrainGeneratorType.h" + +class BoxExtent; +class CollisionInfo; +class IndexedTriangleList; +class Rectangle2d; +class TerrainAppearance; + +//=================================================================== + +class TerrainObject : public Object +{ +public: + + static void install (); + + static TerrainObject* getInstance (); + static const TerrainObject* getConstInstance (); + + static void setUseCache (bool useCache); + + typedef void (*TerrainChangedFunction) (Rectangle2d const & extent2d); + static void addTerrainChangedFunction (TerrainChangedFunction terrainChangedFunction); + static void terrainChanged (Rectangle2d const & extent2d); + +public: + + TerrainObject (); + TerrainObject (const ObjectNotification ¬ification); + virtual ~TerrainObject (); + + bool placeObject (Object& object, bool alignToTerrain=false, bool forceChunkCreation=false) const; + + bool getLogicalHeight (const Vector& position_w, float waterHeight, float& logicalHeight, float& realHeight) const; + bool getLogicalHeight (const Vector& position_w, float waterHeight, float& logicalHeight, float& realHeight, Vector& normal) const; + bool getHeight (const Vector& position_w, float& height) const; + bool getHeight (const Vector& position_w, float& height, Vector& normal) const; + bool getHeightForceChunkCreation (const Vector& position_w, float& height) const; + const ObjectTemplate* getSurfaceProperties (const Vector& position_w) const; + int getTerrainType (const Vector& position_w) const; + bool getWaterHeight (const Vector& position_w, float& height) const; + TerrainGeneratorWaterType getWaterType (const Vector& position_w) const; + bool isBelowWater (const Vector& position_w) const; + bool isBelowWater (const Vector& position_w, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparentWater=false) const; + bool getWaterHeight (const Vector& position_w, float& height, TerrainGeneratorWaterType& waterType, bool ignoreNonTransparenetWater=false) const; + bool getWater (const Rectangle2d& rectangle) const; + bool getSlope (const Rectangle2d& rectangle) const; + bool getWater (int chunkX, int chunkZ) const; + bool getSlope (int chunkX, int chunkZ) const; + + float getMapWidthInMeters () const; + float getMaximumValidHeightInMeters () const; + float getChunkWidthInMeters () const; + int getNumberOfChunks () const; + bool hasHighLevelOfDetailTerrain (const Vector& position_w) const; + int calculateChunkX (const Vector& position_w) const; + int calculateChunkZ (const Vector& position_w) const; + float getChunkHeight (int chunkX, int chunkZ) const; + const BoxExtent* getChunkExtent (const Vector& position_w) const; + const BoxExtent* getChunkExtentForceChunkCreation (const Vector& position_w) const; + + bool collide (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const; + bool collideForceChunkCreation (const Vector& start_w, const Vector& end_w, CollisionInfo& result); + bool collideObjects (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const; + bool approximateCollideObjects (const Vector& start_w, const Vector& end_w, CollisionInfo& result) const; + + void preRender (const Camera* camera) const; + void postRender () const; + + void addReferenceObject (const Object* object); + int getNumberOfReferenceObjects() const; + void removeReferenceObject (const Object* object); + void removeAllReferenceObjects (); + bool isReferenceObject (const Object* object) const; + + bool getPauseEnvironment () const; + void setPauseEnvironment (bool pauseEnvironment); + float getEnvironmentCycleTime () const; + const PackedRgb getClearColor () const; + const PackedRgb getFogColor () const; + float getFogDensity () const; + void getTime (int& hour, int& minute) const; + float getTime () const; + void setTime (float time, bool force=false); + bool isDay () const; + bool isTimeLocked() const; + + typedef stdvector >::fwd ClearFloraEntryList; + void addClearCollidableFloraObject (const Object* object, const Vector& position_w, float radius); + void removeClearCollidableFloraObject (const Object* object); + void addClearNonCollidableFloraObject (const Object* object, const ClearFloraEntryList& clearFloraEntryList); + void removeClearNonCollidableFloraObject (const Object* object); + + static float getHighLevelOfDetailThreshold (); + static void setHighLevelOfDetailThreshold (float highLevelOfDetailThreshold); + static float getLevelOfDetailThreshold (); + static void setLevelOfDetailThreshold (float levelOfDetailThreshold); + + void getPolygonSoup (const Rectangle2d& extent2d_w, IndexedTriangleList& indexedTriangleList) const; + + void invalidateRegion (const Rectangle2d& extent2d); + + //-- debugging + void drawExtents (const Vector& position_w) const; + void purgeChunks(); + +// void writeChunkData (const Vector& position_w) const; +// bool placeObject (Object& object, const Vector& position_w, bool alignToTerrain=false) const; +// bool placeObject (Object& object, const Vector& position_w, const Vector& up_w) const; + + bool isWithinTerrainBoundaries (Vector const &position_w) const; + bool isPassable(Vector const & position_w) const; + bool isPassableForceChunkCreation(Vector const & position_w) const; + + bool hasPassableAffectors() const; + +private: + + static void remove (); + + static void debugDump (); + +private: + + TerrainObject (const TerrainObject&); + TerrainObject& operator= (const TerrainObject&); + +private: + + static TerrainObject* ms_instance; + static bool ms_useCache; + +private: + + mutable Vector2d m_cachedPosition_w; + mutable float m_cachedPositionHeight; + mutable Vector2d m_cachedPositionNormal_w; + mutable float m_cachedPositionNormalHeight; + mutable Vector m_cachedPositionNormalNormal_w; + mutable Vector2d m_cachedPositionWater_w; + mutable float m_cachedPositionWaterHeight; + mutable TerrainGeneratorWaterType m_cachedPositionWaterType; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.cpp b/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.cpp new file mode 100644 index 00000000..9dbcb8aa --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.cpp @@ -0,0 +1,87 @@ +//=================================================================== +// +// TerrainReferenceObjectNotification.cpp +// asommers +// +// copyright 2001, sony online entertainment +// +//=================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h" +#include "sharedTerrain/TerrainReferenceObjectNotification.h" + +#include "sharedTerrain/TerrainObject.h" + +//=================================================================== + +TerrainReferenceObjectNotification TerrainReferenceObjectNotification::ms_instance; + +//=================================================================== + +TerrainReferenceObjectNotification& TerrainReferenceObjectNotification::getInstance () +{ + return ms_instance; +} + +//=================================================================== + +TerrainReferenceObjectNotification::TerrainReferenceObjectNotification () : + ObjectNotification () +{ +} + +//------------------------------------------------------------------- + +TerrainReferenceObjectNotification::~TerrainReferenceObjectNotification () +{ +} + +//------------------------------------------------------------------- + +void TerrainReferenceObjectNotification::addToWorld (Object& object) const +{ + //-- if there is no terrain, return + if (!TerrainObject::getInstance ()) + return; + + if (object.isInWorldCell ()) + TerrainObject::getInstance ()->addReferenceObject (&object); +} + +//------------------------------------------------------------------- + +void TerrainReferenceObjectNotification::removeFromWorld (Object& object) const +{ + //-- if there is no terrain, return + if (!TerrainObject::getInstance ()) + return; + + if (object.isInWorldCell ()) + TerrainObject::getInstance ()->removeReferenceObject (&object); +} + +//------------------------------------------------------------------- + +void TerrainReferenceObjectNotification::cellChanged (Object& object, bool /*dueToParentChange*/) const +{ + //-- if there is no terrain, return + if (!TerrainObject::getInstance ()) + return; + + //-- if the object is in the world cell + if (object.isInWorldCell ()) + { + //-- and not a reference object, add it + if (!TerrainObject::getInstance ()->isReferenceObject (&object)) + addToWorld (object); + } + else + { + //-- otherwise, if it is a reference object, remove it + if (TerrainObject::getInstance ()->isReferenceObject (&object)) + removeFromWorld (object); + } +} + +//=================================================================== + diff --git a/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.h b/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.h new file mode 100644 index 00000000..f86f264d --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/shared/object/TerrainReferenceObjectNotification.h @@ -0,0 +1,46 @@ +//=================================================================== +// +// TerrainReferenceObjectNotification.h +// asommers +// +// copyright 2003, sony online entertainment +// +//=================================================================== + +#ifndef INCLUDED_TerrainReferenceObjectNotification_H +#define INCLUDED_TerrainReferenceObjectNotification_H + +//=================================================================== + +#include "sharedObject/ObjectNotification.h" + +//=================================================================== + +class TerrainReferenceObjectNotification : public ObjectNotification +{ +public: + + static TerrainReferenceObjectNotification& getInstance (); + +public: + + TerrainReferenceObjectNotification (); + virtual ~TerrainReferenceObjectNotification (); + + virtual void addToWorld (Object& object) const; + virtual void removeFromWorld (Object& object) const; + virtual void cellChanged (Object& object, bool dueToParentChange) const; + +private: + + TerrainReferenceObjectNotification (const TerrainReferenceObjectNotification&); + TerrainReferenceObjectNotification& operator= (const TerrainReferenceObjectNotification&); + +private: + + static TerrainReferenceObjectNotification ms_instance; +}; + +//=================================================================== + +#endif diff --git a/engine/shared/library/sharedTerrain/src/win32/FirstSharedTerrain.cpp b/engine/shared/library/sharedTerrain/src/win32/FirstSharedTerrain.cpp new file mode 100644 index 00000000..b8b5d9c2 --- /dev/null +++ b/engine/shared/library/sharedTerrain/src/win32/FirstSharedTerrain.cpp @@ -0,0 +1,8 @@ +// ====================================================================== +// +// FirstTerrain.cpp +// copyright (c) 2001 Sony Online Entertainment +// +// ====================================================================== + +#include "sharedTerrain/FirstSharedTerrain.h"