001package squidpony.squidgrid.gui.gdx; 002 003import com.badlogic.gdx.graphics.Color; 004import squidpony.ArrayTools; 005import squidpony.squidgrid.gui.gdx.ICellVisible.Basic; 006import squidpony.squidgrid.mapping.WildMap; 007import squidpony.squidgrid.mapping.WorldMapGenerator; 008import squidpony.squidmath.IntPointHash; 009import squidpony.squidmath.SilkRNG; 010 011import java.util.HashMap; 012import java.util.Map; 013 014import static squidpony.squidgrid.gui.gdx.SColor.*; 015import static squidpony.squidgrid.gui.gdx.WorldMapView.*; 016 017/** 018 * Created by Tommy Ettinger on 9/6/2019. 019 */ 020public class WildMapView { 021 protected int width, height; 022 protected float[][] colorMap; 023 public WildMap wildMap; 024 025 public Map<String, ? extends ICellVisible> viewer; 026 027 public int getWidth() { 028 return width; 029 } 030 031 public int getHeight() { 032 return height; 033 } 034 035 public float[][] getColorMap() { 036 return colorMap; 037 } 038 039 public WildMap getWildMap() { 040 return wildMap; 041 } 042 043 public void setWildMap(WildMap wildMap) { 044 this.wildMap = wildMap; 045 if(this.width != wildMap.width || this.height != wildMap.height) 046 { 047 width = wildMap.width; 048 height = wildMap.height; 049 colorMap = new float[width][height]; 050 } 051 } 052 053 public static HashMap<String, ? extends ICellVisible> defaultViewer() 054 { 055 HashMap<String, ICellVisible> viewer = new HashMap<>(128); 056 057 viewer.put("snow path", new Basic('.', ALICE_BLUE.toEditedFloat(0.0f, -0.2f, -0.15f))); 058 viewer.put("dirt path", new Basic('.', CLOVE_BROWN.toEditedFloat(-0.005f, -0.275f, 0.17f))); 059 viewer.put("sand path", new Basic('.', CW_PALE_ORANGE.toEditedFloat(0.05f, -0.17f, -0.075f))); 060 viewer.put("grass path", new Basic('.', AURORA_DUSTY_GREEN.toEditedFloat(0.0f, -0.15f, -0.1f))); 061 viewer.put("stone path", new Basic('.', AURORA_CHIPPED_GRANITE.toEditedFloat(-0.09f, -0.05f, 0.1f))); 062 viewer.put("wooden bridge", new Basic(':', BRUSHWOOD_DYED.toEditedFloat(0.0f, -0.275f, 0.05f))); 063 064 viewer.put("ice ledge", new Basic('¬', SColor.toEditedFloat(PALE_CORNFLOWER_BLUE, 0.0f, -0.1f, 0.1f))); 065 viewer.put("dirt ledge", new Basic('¬', CLOVE_BROWN.toEditedFloat(-0.005f, -0.175f, -0.18f))); 066 viewer.put("sand ledge", new Basic('¬', CW_PALE_ORANGE.toEditedFloat(0.05f, -0.15f, -0.125f))); 067 viewer.put("grass ledge", new Basic('¬', AURORA_DUSTY_GREEN.toEditedFloat(0.0f, -0.025f, -0.45f))); 068 viewer.put("stone ledge", new Basic('¬', AURORA_CHIPPED_GRANITE.toEditedFloat(-0.07f, -0.1f, -0.25f))); 069 070 viewer.put("snow", new Basic('…', ALICE_BLUE)); 071 viewer.put("ice", new Basic('-', SColor.lightenFloat(PALE_CORNFLOWER_BLUE, 0.3f))); 072 viewer.put("dirt", new Basic('·', CLOVE_BROWN.toEditedFloat(-0.005f, -0.075f, 0.02f))); 073 viewer.put("pebbles", new Basic('…', AURORA_WET_STONE.toEditedFloat(0.0f, 0.0f, 0.0f))); 074 viewer.put("dry grass", new Basic('\'', CW_FADED_BROWN.toEditedFloat(0.06f, 0.05f, 0.05f))); 075 viewer.put("fresh water", new Basic('~', AURORA_BLUE_EYE)); 076 viewer.put("salt water", new Basic('≈', AURORA_PRUSSIAN_BLUE)); 077 viewer.put("sand", new Basic('…', CW_PALE_ORANGE.toEditedFloat(0.05f, -0.05f, 0.075f))); 078 viewer.put("leaves", new Basic('…', CHINESE_TEA_YELLOW.toEditedFloat(0.02f, -0.025f, 0.0f))); 079 viewer.put("grass", new Basic('"', AURORA_DUSTY_GREEN.toEditedFloat(0.0f, 0.075f, -0.25f))); 080 viewer.put("mud", new Basic(',', DB_EARTH.toEditedFloat(0.03f, -0.15f, -0.03f))); 081 viewer.put("moss", new Basic('˝', AURORA_FERN_GREEN.toEditedFloat(0f, 0.0f, 0.0f))); 082 viewer.put("rubble", new Basic('‰', AURORA_CHIPPED_GRANITE.toEditedFloat(-0.07f, 0.0f, -0.05f))); 083 viewer.put("empty space", new Basic('_', DB_INK)); 084 viewer.put("snow mound", new Basic('∆', ALICE_BLUE.toEditedFloat(0f, 0.05f, -0.1f))); 085 viewer.put("icy divot", new Basic('°', ALICE_BLUE.toEditedFloat(0.05f, 0.075f, 0.06f))); 086 viewer.put("powder snowdrift", new Basic('¨', ALICE_BLUE.toEditedFloat(0.0f, 0.0f, -0.07f))); 087 viewer.put("hillock", new Basic('∆', CW_DRAB_BROWN.toEditedFloat(0.1f, -0.05f, 0.25f))); 088 viewer.put("animal burrow", new Basic('¸', AURORA_ARMY_GREEN.toEditedFloat(0.05f, 0.0f, -0.05f))); 089 viewer.put("small bush 1", new Basic('♣', AURORA_AVOCADO.toEditedFloat(-0.055f, -0.025f, -0.225f))); 090 viewer.put("large bush 1", new Basic('♣', AURORA_FOREST_GLEN.toEditedFloat(-0.055f, -0.125f, -0.225f))); 091 viewer.put("evergreen tree 1", new Basic('♠', PINE_GREEN.toEditedFloat(-0.13f, -0.03f, -0.05f))); 092 viewer.put("evergreen tree 2", new Basic('♠', AURORA_EUCALYPTUS.toEditedFloat(-0.035f, -0.045f, -0.75f))); 093 viewer.put("small cactus 1", new Basic('‡', AURORA_FROG_GREEN.toEditedFloat(0.035f, 0.065f, -0.06f))); 094 viewer.put("large cactus 1", new Basic('‡', AURORA_MARSH.toEditedFloat(0.04f, 0.11f, -0.03f))); 095 viewer.put("succulent 1", new Basic('§', CW_FLUSH_JADE.toEditedFloat(-0.045f, -0.1f, 0.0f))); 096 viewer.put("seashell 1", new Basic('ˋ', CW_LIGHT_APRICOT.toEditedFloat(0.0f, -0.095f, 0.07f))); 097 viewer.put("seashell 2", new Basic('ˋ', CW_PALE_RED.toEditedFloat(0.0f, -0.2f, 0.1f))); 098 viewer.put("seashell 3", new Basic('ˋ', CW_PALE_YELLOW.toEditedFloat(0.0f, 0.02f, 0.05f))); 099 viewer.put("seashell 4", new Basic('ˋ', CW_PALE_VIOLET.toEditedFloat(0.0f, -0.080f, 0.11f))); 100 viewer.put("driftwood", new Basic('¿', AURORA_DRIFTWOOD.toEditedFloat(0.0f, -0.25f, 0.04f))); 101 viewer.put("boulder", new Basic('●', AURORA_SLOW_CREEK.toEditedFloat(0.0f, -0.01f, 0.0f))); 102 viewer.put("deciduous tree 1", new Basic('¥', AURORA_AVOCADO.toEditedFloat(-0.065f, 0.0f, -0.3f))); 103 viewer.put("small bush 2", new Basic('♣', AURORA_WOODLANDS.toEditedFloat(-0.045f, -0.05f, -0.025f))); 104 viewer.put("deciduous tree 2", new Basic('¥', AURORA_IVY_GREEN.toEditedFloat(-0.02f, 0.0f, 0.0f))); 105 viewer.put("deciduous tree 3", new Basic('¥', AURORA_ASPARAGUS.toEditedFloat(-0.015f, 0.055f, 0.02f))); 106 viewer.put("large bush 2", new Basic('♣', AURORA_VIRIDIAN.toEditedFloat(-0.03f, -0.05f, 0.03f))); 107 viewer.put("tropical tree 1", new Basic('¶', AURORA_FLORAL_FOAM.toEditedFloat(-0.05f, 0.025f, 0.075f))); 108 viewer.put("tropical tree 2", new Basic('¶', AURORA_MAIDENHAIR_FERN.toEditedFloat(0.0f, 0.0f, 0.02f))); 109 viewer.put("large bush 3", new Basic('♣', AURORA_KELLY_GREEN.toEditedFloat(0.0f, 0.025f, 0.02f))); 110 viewer.put("tropical tree 3", new Basic('¶', AURORA_SOFT_TEAL.toEditedFloat(-0.15f, -0.07f, -0.03f))); 111 viewer.put("tropical tree 4", new Basic('¶', AURORA_PRASE.toEditedFloat(-0.04f, -0.02f, -0.02f))); 112 return viewer; 113 } 114 115 public WildMapView() 116 { 117 this(null); 118 } 119 public WildMapView(WildMap wildMap) 120 { 121 if(wildMap == null) 122 { 123 this.wildMap = new WildMap(); 124 } 125 else 126 { 127 this.wildMap = wildMap; 128 } 129 this.viewer = defaultViewer(); 130 width = this.wildMap.width; 131 height = this.wildMap.height; 132 colorMap = new float[width][height]; 133 initialize(); 134 } 135 public WildMapView(WildMap wildMap, Map<String, ? extends ICellVisible> viewer) 136 { 137 if(wildMap == null) { // default to forest map, biome 21; ignore given viewer, it may be null 138 this.wildMap = new WildMap(); 139 this.viewer = defaultViewer(); 140 } 141 else 142 { 143 this.wildMap = wildMap; 144 this.viewer = viewer == null ? defaultViewer() : viewer; 145 } 146 width = this.wildMap.width; 147 height = this.wildMap.height; 148 colorMap = new float[width][height]; 149 initialize(); 150 } 151 152 public WildMapView(long seed, int width, int height, int biome) 153 { 154 this(new WildMap(width, height, biome, new SilkRNG(seed))); 155 } 156 157 protected float[] biomeColors = { 158 desertColor, 159 savannaColor, 160 tropicalRainforestColor, 161 grasslandColor, 162 woodlandColor, 163 seasonalForestColor, 164 temperateRainforestColor, 165 borealForestColor, 166 tundraColor, 167 iceColor, 168 beachColor, 169 rockyColor, 170 shallowColor, 171 deepColor, 172 emptyColor 173 }; 174 public final float[] BIOME_COLOR_TABLE = new float[61], BIOME_DARK_COLOR_TABLE = new float[61]; 175 176 public void initialize() 177 { 178 initialize(0f, 0f, 0f, 1f); 179 } 180 181 public void initialize(float hue, float saturation, float brightness, float contrast) 182 { 183 float b, diff; 184 for (int i = 0; i < 60; i++) { 185 b = BIOME_TABLE[i]; 186 diff = (b % 1.0f - 0.48f) * 0.27f * contrast; 187 BIOME_COLOR_TABLE[i] = b = SColor.toEditedFloat(diff >= 0 188 ? SColor.lightenFloat(biomeColors[(int)b], diff) 189 : SColor.darkenFloat(biomeColors[(int)b], -diff), hue, saturation, brightness, 0f); 190 BIOME_DARK_COLOR_TABLE[i] = SColor.darkenFloat(b, 0.08f); 191 } 192 BIOME_COLOR_TABLE[60] = BIOME_DARK_COLOR_TABLE[60] = emptyColor; 193 } 194 195 /** 196 * Initializes the colors to use for each biome (these are almost always mixed with other biome colors in practice). 197 * Each parameter may be null to use the default for an Earth-like world; otherwise it should be a libGDX 198 * {@link Color} or some subclass, like {@link SColor}. All non-null parameters should probably be fully opaque, 199 * except {@code emptyColor}, which is only used for world maps that show empty space (like a globe, as produced by 200 * {@link WorldMapGenerator.RotatingSpaceMap}). 201 * @param desertColor hot, dry, barren land; may be sandy, but many real-world deserts don't have much sand 202 * @param savannaColor hot, mostly-dry land with some parched vegetation; also called scrub or chaparral 203 * @param tropicalRainforestColor hot, extremely wet forests with dense rich vegetation 204 * @param grasslandColor prairies that are dry and usually wind-swept, but not especially hot or cold 205 * @param woodlandColor part-way between a prairie and a forest; not especially hot or cold 206 * @param seasonalForestColor forest that becomes barren in winter (deciduous trees); not especially hot or cold 207 * @param temperateRainforestColor forest that tends to be slightly warm but very wet 208 * @param borealForestColor forest that tends to be cold and very wet 209 * @param tundraColor very cold plains that still have some low-lying vegetation; also called taiga 210 * @param iceColor cold barren land covered in permafrost; also used for rivers and lakes that are frozen 211 * @param beachColor sandy or otherwise light-colored shorelines; here, these are more common in warmer places 212 * @param rockyColor rocky or otherwise rugged shorelines; here, these are more common in colder places 213 * @param shallowColor the color of very shallow water; will be mixed with {@code deepColor} to get most ocean colors 214 * @param deepColor the color of very deep water; will be mixed with {@code shallowColor} to get most ocean colors 215 * @param emptyColor the color used for empty space off the edge of the world map; may be transparent 216 */ 217 public void initialize( 218 Color desertColor, 219 Color savannaColor, 220 Color tropicalRainforestColor, 221 Color grasslandColor, 222 Color woodlandColor, 223 Color seasonalForestColor, 224 Color temperateRainforestColor, 225 Color borealForestColor, 226 Color tundraColor, 227 Color iceColor, 228 Color beachColor, 229 Color rockyColor, 230 Color shallowColor, 231 Color deepColor, 232 Color emptyColor 233 ) 234 { 235 biomeColors[ 0] = desertColor == null ? WorldMapView.desertColor : desertColor.toFloatBits(); 236 biomeColors[ 1] = savannaColor == null ? WorldMapView.savannaColor : savannaColor.toFloatBits(); 237 biomeColors[ 2] = tropicalRainforestColor == null ? WorldMapView.tropicalRainforestColor : tropicalRainforestColor.toFloatBits(); 238 biomeColors[ 3] = grasslandColor == null ? WorldMapView.grasslandColor : grasslandColor.toFloatBits(); 239 biomeColors[ 4] = woodlandColor == null ? WorldMapView.woodlandColor : woodlandColor.toFloatBits(); 240 biomeColors[ 5] = seasonalForestColor == null ? WorldMapView.seasonalForestColor : seasonalForestColor.toFloatBits(); 241 biomeColors[ 6] = temperateRainforestColor == null ? WorldMapView.temperateRainforestColor : temperateRainforestColor.toFloatBits(); 242 biomeColors[ 7] = borealForestColor == null ? WorldMapView.borealForestColor : borealForestColor.toFloatBits(); 243 biomeColors[ 8] = tundraColor == null ? WorldMapView.tundraColor : tundraColor.toFloatBits(); 244 biomeColors[ 9] = iceColor == null ? WorldMapView.iceColor : iceColor.toFloatBits(); 245 biomeColors[10] = beachColor == null ? WorldMapView.beachColor : beachColor.toFloatBits(); 246 biomeColors[11] = rockyColor == null ? WorldMapView.rockyColor : rockyColor.toFloatBits(); 247 biomeColors[12] = shallowColor == null ? WorldMapView.shallowColor : shallowColor.toFloatBits(); 248 biomeColors[13] = deepColor == null ? WorldMapView.deepColor : deepColor.toFloatBits(); 249 biomeColors[14] = emptyColor == null ? WorldMapView.emptyColor : emptyColor.toFloatBits(); 250 float b, diff; 251 for (int i = 0; i < 60; i++) { 252 b = BIOME_TABLE[i]; 253 diff = (b % 1.0f - 0.48f) * 0.27f; 254 BIOME_COLOR_TABLE[i] = b = diff >= 0 255 ? SColor.lightenFloat(biomeColors[(int)b], diff) 256 : SColor.darkenFloat(biomeColors[(int)b], -diff); 257 BIOME_DARK_COLOR_TABLE[i] = SColor.darkenFloat(b, 0.08f); 258 } 259 BIOME_COLOR_TABLE[60] = BIOME_DARK_COLOR_TABLE[60] = biomeColors[14]; 260 biomeColors[ 0] = WorldMapView.desertColor; 261 biomeColors[ 1] = WorldMapView.savannaColor; 262 biomeColors[ 2] = WorldMapView.tropicalRainforestColor; 263 biomeColors[ 3] = WorldMapView.grasslandColor; 264 biomeColors[ 4] = WorldMapView.woodlandColor; 265 biomeColors[ 5] = WorldMapView.seasonalForestColor; 266 biomeColors[ 6] = WorldMapView.temperateRainforestColor; 267 biomeColors[ 7] = WorldMapView.borealForestColor; 268 biomeColors[ 8] = WorldMapView.tundraColor; 269 biomeColors[ 9] = WorldMapView.iceColor; 270 biomeColors[10] = WorldMapView.beachColor; 271 biomeColors[11] = WorldMapView.rockyColor; 272 biomeColors[12] = WorldMapView.shallowColor; 273 biomeColors[13] = WorldMapView.deepColor; 274 biomeColors[14] = WorldMapView.emptyColor; 275 } 276 277 278 public void generate() 279 { 280 wildMap.generate(); 281 float baseColor = BIOME_COLOR_TABLE[wildMap.biome & 1023]; 282 int h = 1234567890, change, seed = wildMap.rng.nextInt(); 283 ICellVisible icv; 284 for (int x = 0; x < width; x++) { 285 for (int y = 0; y < height; y++) { 286 change = h += IntPointHash.hashAll(x, y, 287 seed); 288 if((icv = viewer.get(wildMap.floorTypes.get(wildMap.floors[x][y]))) != null) 289 colorMap[x][y] = SColor.toEditedFloat(icv.getPackedColor(), 290 0x1p-12f * ((h & 0xFF) - 0x9F + (change >>> 8 & 0x3F)), 291 0x1.8p-12f * ((h >>> 8 & 0xFF) - 0xB0 + (change >>> 16 & 0x3F)) - 0.0625f, 292 0x1.3p-12f * ((h >>> 16 & 0xFF) - 0x90 + (change >>> 24 & 0x3F)), 293 0f); 294 else 295 colorMap[x][y] = SColor.toEditedFloat(baseColor, 296 0x1p-12f * ((h & 0xFF) - 0x9F + (change >>> 8 & 0x3F)), 297 0x1.8p-12f * ((h >>> 8 & 0xFF) - 0xB0 + (change >>> 16 & 0x3F)) - 0.0625f, 298 0x1.3p-12f * ((h >>> 16 & 0xFF) - 0x90 + (change >>> 24 & 0x3F)), 299 0f); 300 301 } 302 } 303 } 304 305 public void show(SparseLayers layers) 306 { 307 ArrayTools.insert(colorMap, layers.backgrounds, 0, 0); 308 int c; 309 ICellVisible icv; 310 for (int x = 0; x < width && x < layers.gridWidth; x++) { 311 for (int y = 0; y < height && y < layers.gridHeight; y++) { 312 if((c = wildMap.content[x][y]) >= 0 && (icv = viewer.get(wildMap.contentTypes.get(c))) != null) 313 layers.put(x, y, icv.getSymbol(), SColor.contrastLuma(icv.getPackedColor(), colorMap[x][y])); 314 else if((icv = viewer.get(wildMap.floorTypes.get(wildMap.floors[x][y]))) != null) 315 layers.put(x, y, icv.getSymbol(), SColor.contrastLuma(icv.getPackedColor(), colorMap[x][y])); 316 } 317 } 318 } 319}