/// <summary> /// Cache index to the list of scaled shapeable typeface /// </summary> private void CacheScaledTypefaceMap( CharacterBufferRange unicodeString, CultureInfo culture, CultureInfo digitCulture, SpanVector scaledTypefaceSpans, ref SpanVector <int> cachedScaledTypefaceIndexSpans, int ichItem ) { IntMap map; if (!_intMaps.TryGetValue(culture, out map)) { map = new IntMap(); _intMaps.Add(culture, map); } DigitMap digitMap = new DigitMap(digitCulture); SpanRider typefaceSpanRider = new SpanRider(scaledTypefaceSpans); int ich = 0; while (ich < unicodeString.Length) { typefaceSpanRider.At(ich); int cch = Math.Min(unicodeString.Length - ich, typefaceSpanRider.Length); int index = IndexOfScaledTypeface((ScaledShapeTypeface)typefaceSpanRider.CurrentElement); Debug.Assert(index >= 0, "Invalid scaled shapeable typeface index spans"); cachedScaledTypefaceIndexSpans.Set(ichItem + ich, cch, index); // we keep index + 1 in the map, so that we leave map entry zero // to indicate uninitialized entry. index++; int sizeofChar; for (int c = 0; c < cch; c += sizeofChar) { int ch = digitMap[ Classification.UnicodeScalar( new CharacterBufferRange(unicodeString, ich + c, unicodeString.Length - ich - c), out sizeofChar ) ]; // only cache typeface map index for base characters if (!Classification.IsCombining(ch) && !Classification.IsJoiner(ch)) { // Dump values of local variables when the condition fails for better debuggability. // We use "if" to avoid the expensive string.Format() in normal case. if (map[ch] != 0 && map[ch] != index) { Invariant.Assert( false, string.Format( CultureInfo.InvariantCulture, "shapeable cache stores conflicting info, ch = {0}, map[ch] = {1}, index = {2}", ch, map[ch], index ) ); } map[ch] = (ushort)index; } } ich += cch; } }
public void genBlockColumn(IServerChunk[] chunks, int chunkX, int chunkZ, int lx, int lz) { int surfaceY = heightMap[lz * chunksize + lx]; int ylower = 1; int yupper = surfaceY; strataThickness = 0; WeightedIndex[] indices = map[ chunkInRegionX + lx * lerpMapInv, chunkInRegionZ + lz * lerpMapInv ]; rockGroupMaxThickness[0] = rockGroupMaxThickness[1] = rockGroupMaxThickness[2] = rockGroupMaxThickness[3] = 0; rockGroupCurrentThickness[0] = rockGroupCurrentThickness[1] = rockGroupCurrentThickness[2] = rockGroupCurrentThickness[3] = 0; for (int i = 0; i < indices.Length; i++) { float w = indices[i].Weight; GeologicProvinceVariant var = provinces.Variants[indices[i].Index]; rockGroupMaxThickness[0] += var.RockStrataIndexed[0].MaxThickness * w; rockGroupMaxThickness[1] += var.RockStrataIndexed[1].MaxThickness * w; rockGroupMaxThickness[2] += var.RockStrataIndexed[2].MaxThickness * w; rockGroupMaxThickness[3] += var.RockStrataIndexed[3].MaxThickness * w; } float distx = (float)distort2dx.Noise(chunkX * chunksize + lx, chunkZ * chunksize + lz); float distz = (float)distort2dz.Noise(chunkX * chunksize + lx, chunkZ * chunksize + lz); rockStrataId = -1; while (ylower <= yupper) { if (--strataThickness <= 0) { rockStrataId++; if (rockStrataId >= strata.Variants.Length) { break; } stratum = strata.Variants[rockStrataId]; rockMap = mapChunk.MapRegion.RockStrata[rockStrataId]; step = (float)rockMap.InnerSize / regionChunkSize; grp = (int)stratum.RockGroup; float thicknessDistort = GameMath.Clamp((distx + distz) / 30, 0.9f, 1.1f); float allowedThickness = rockGroupMaxThickness[grp] * thicknessDistort - rockGroupCurrentThickness[grp]; strataThickness = Math.Min(allowedThickness, rockMap.GetIntLerpedCorrectly(rdx * step + step * (float)(lx + distx) / chunksize, rdz * step + step * (float)(lz + distz) / chunksize)); strataThickness -= (stratum.RockGroup == EnumRockGroup.Sedimentary) ? Math.Max(0, yupper - TerraGenConfig.seaLevel) * 0.5f : 0; if (strataThickness < 2) { strataThickness = -1; continue; } } rockGroupCurrentThickness[grp]++; if (stratum.GenDir == EnumStratumGenDir.BottomUp) { int chunkY = ylower / chunksize; int lY = ylower - chunkY * chunksize; int localIndex3D = (chunksize * lY + lz) * chunksize + lx; if (chunks[chunkY].Blocks[localIndex3D] == rockBlockId) { chunks[chunkY].Blocks[localIndex3D] = stratum.BlockId; } ylower++; } else { int chunkY = yupper / chunksize; int lY = yupper - chunkY * chunksize; int localIndex3D = (chunksize * lY + lz) * chunksize + lx; if (chunks[chunkY].Blocks[localIndex3D] == rockBlockId) { chunks[chunkY].Blocks[localIndex3D] = stratum.BlockId; } yupper--; } } }
private void OnChunkColumnGeneration(IServerChunk[] chunks, int chunkX, int chunkZ) { IntMap forestMap = chunks[0].MapChunk.MapRegion.ForestMap; IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; // "Pixels per chunk" float facF = (float)forestMap.InnerSize / regionChunkSize; // Retrieves the map data on the chunk edges int forestUpLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF)); int forestUpRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF)); int forestBotLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF)); int forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF)); float facC = (float)climateMap.InnerSize / regionChunkSize; int climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC)); int climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC)); int climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC)); int climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC)); for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { int posY = heightMap[z * chunksize + x]; int climate = GameMath.BiLerpRgbColor((float)x / chunksize, (float)z / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); int tempUnscaled = (climate >> 16) & 0xff; float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; int prevY = posY; posY = PutLayers(x, posY, z, chunks, rainRel, temp, tempUnscaled, heightMap); PlaceTallGrass(x, prevY, z, chunks, rainRel, temp, forestRel); // Try again to put layers if above sealevel and we found over 10 air blocks int foundAir = 0; while (posY >= TerraGenConfig.seaLevel - 1) { int chunkY = posY / chunksize; int lY = posY % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; ushort blockId = chunks[chunkY].Blocks[index3d]; if (blockId == 0) { foundAir++; } else { if (foundAir >= 8) { temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; PutLayers(x, posY, z, chunks, rainRel, temp, tempUnscaled, null); break; } else { foundAir = 0; } } posY--; } } } }
/// <summary> /// forceInitialPosY is for subdeposits /// </summary> /// <param name="chunks"></param> /// <param name="chunkX"></param> /// <param name="chunkZ"></param> /// <param name="offsetX"></param> /// <param name="offsetZ"></param> /// <param name="variant"></param> /// <param name="forceInitialPosY"></param> /// <returns></returns> Dictionary <Vec3i, DepositVariant> GenDeposit(IServerChunk[] chunks, int chunkX, int chunkZ, int offsetX, int offsetZ, DepositVariant variant, int?forceInitialPosY = null) { Dictionary <Vec3i, DepositVariant> SubDepositsToPlace = new Dictionary <Vec3i, DepositVariant>(); IMapChunk mapchunk = chunks[0].MapChunk; int radius = Math.Min(64, (int)variant.Radius.nextFloat(1, depositRand)); if (radius <= 0) { return(SubDepositsToPlace); } // Let's deform that perfect circle a bit (+/- 25%) float deform = GameMath.Clamp(depositRand.NextFloat() - 0.5f, -0.25f, 0.25f); int radiusX = radius - (int)(radius * deform); int radiusZ = radius + (int)(radius * deform); int posY; // No need to caluclate further if this deposit won't be part of this chunk if (radiusX + offsetX < 0 || radiusZ + offsetZ < 0 || offsetX - radiusX >= chunksize || offsetZ - radiusZ >= chunksize) { return(SubDepositsToPlace); } IMapChunk originMapchunk = null; int origPosY = 0; int lx = GameMath.Mod(offsetX, chunksize); int lz = GameMath.Mod(offsetZ, chunksize); if (variant.MaxY < 1 || variant.CheckClimate) { originMapchunk = api.WorldManager.GetMapChunk((chunkX * chunksize + offsetX) / chunksize, (chunkZ * chunksize + offsetZ) / chunksize); if (originMapchunk == null) { return(SubDepositsToPlace); // argh >.< } origPosY = originMapchunk.RainHeightMap[lz * chunksize + lx]; if ((float)origPosY / api.World.BlockAccessor.MapSizeY > variant.MaxY) { return(SubDepositsToPlace); } } // Check if suited for this area, climate wise if (variant.CheckClimate) { IntMap climateMap = api.World.BlockAccessor.GetMapRegion((chunkX * chunksize + offsetX) / regionSize, (chunkZ * chunksize + offsetZ) / regionSize).ClimateMap; float posXInRegionClimate = ((float)lx / regionSize - lx / regionSize) * noiseSizeClimate; float posZInRegionClimate = ((float)lz / regionSize - lz / regionSize) * noiseSizeClimate; int climate = climateMap.GetUnpaddedColorLerped(posXInRegionClimate, posZInRegionClimate); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, origPosY - TerraGenConfig.seaLevel); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, origPosY) / 255f; if (rainRel < variant.MinRain || rainRel > variant.MaxRain || temp < variant.MinTemp || temp > variant.MaxTemp) { return(SubDepositsToPlace); } } // Ok generate float th = variant.Thickness.nextFloat(1, depositRand); int thickness = (int)th + (depositRand.NextFloat() < th - (int)th ? 1 : 0); float xRadSqInv = 1f / (radiusX * radiusX); float zRadSqInv = 1f / (radiusZ * radiusZ); int blockIndex = 0; bool parentBlockOk = false; float depthf; bool shouldGenSurfaceDeposit = depositRand.NextFloat() > 0.35f && variant.SurfaceBlockCode != null; if (forceInitialPosY != null) { depthf = (float)forceInitialPosY / mapchunk.WorldGenTerrainHeightMap[offsetX * chunksize + offsetZ]; } else { depthf = variant.Depth.nextFloat(1, depositRand); } int depthi = (int)depthf; int topLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int topRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int botLeft = 2 * depositRand.NextInt(radiusX + 1) - radiusX; int botRight = 2 * depositRand.NextInt(radiusZ + 1) - radiusZ; int yOff = 0; // Only generate inside this current chunk column int minx = GameMath.Clamp(offsetX - radiusX, 0, chunksize); int maxx = GameMath.Clamp(offsetX + radiusX, 0, chunksize); int minz = GameMath.Clamp(offsetZ - radiusZ, 0, chunksize); int maxz = GameMath.Clamp(offsetZ + radiusZ, 0, chunksize); float invChunkAreaSize = 1f / (chunksize * chunksize); for (int x = minx; x < maxx; x++) { float xSq = (x - offsetX) * (x - offsetX) * xRadSqInv; for (int z = minz; z < maxz; z++) { if (xSq + (z - offsetZ) * (z - offsetZ) * zRadSqInv > 1) { continue; } if (variant.Placement == EnumDepositPlacement.FollowSurfaceBelow) { posY = mapchunk.WorldGenTerrainHeightMap[z * chunksize + x] - depthi; } else if (variant.Placement == EnumDepositPlacement.FollowSurface) { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]) + yOff / 2; } else if (variant.Placement == EnumDepositPlacement.Straight) { posY = (int)(depthf * mapchunk.WorldGenTerrainHeightMap[z * chunksize + x]); } else { yOff = (int)GameMath.BiLerp(topLeft, topRight, botLeft, botRight, (x - offsetX + radiusX) / (2f * radiusX), (z - offsetZ + radiusZ) / (2f * radiusZ)); posY = depthi + yOff; } // Some deposits may not appear all over cliffs if (variant.CheckClimate && Math.Abs(origPosY - posY) > variant.MaxYRoughness) { continue; } for (int y = 0; y < thickness; y++) { if (posY <= 1 || posY >= worldheight) { continue; } long index3d = ((posY % chunksize) * chunksize + z) * chunksize + x; ushort blockId = chunks[posY / chunksize].Blocks[index3d]; // Check if we are in mother material, but only if it has changed since last iteration (should reduce amount of these checks by 50-100%) parentBlockOk = false; for (int i = 0; i < variant.ParentBlockIds.Length; i++) { if (variant.ParentBlockIds[i] == blockId) { parentBlockOk = true; blockIndex = i; break; } } if (parentBlockOk) { if (variant.WithBlockCallback) { tmpPos.Set(chunkX * chunksize + x, posY, chunkZ * chunksize + z); blockTypes[variant.BlockIds[blockIndex]].TryPlaceBlockForWorldGen(blockAccessor, tmpPos, BlockFacing.UP); } else { chunks[posY / chunksize].Blocks[index3d] = variant.BlockIds[blockIndex]; } for (int i = 0; i < variant.ChildDeposits.Length; i++) { float rndVal = depositRand.NextFloat(); float quantity = variant.ChildDeposits[i].Quantity * invChunkAreaSize; if (quantity > rndVal) { Vec3i pos = new Vec3i(x, posY, z); if (ShouldPlaceAdjustedForOreMap(variant.ChildDeposits[i], chunkX * chunksize + x, chunkZ * chunksize + z, quantity, rndVal)) { SubDepositsToPlace[pos] = variant.ChildDeposits[i]; } } } if (shouldGenSurfaceDeposit) { int surfaceY = mapchunk.RainHeightMap[z * chunksize + x]; int depth = surfaceY - posY; float chance = variant.SurfaceBlockChance * Math.Max(0, 1 - depth / 8f); if (depositRand.NextFloat() < chance) { index3d = (((surfaceY + 1) % chunksize) * chunksize + z) * chunksize + x; Block belowBlock = api.World.Blocks[chunks[surfaceY / chunksize].Blocks[((surfaceY % chunksize) * chunksize + z) * chunksize + x]]; if (belowBlock.SideSolid[BlockFacing.UP.Index] && chunks[(surfaceY + 1) / chunksize].Blocks[index3d] == 0) { chunks[(surfaceY + 1) / chunksize].Blocks[index3d] = variant.SurfaceBlockIds[blockIndex]; } } } } posY--; } } } return(SubDepositsToPlace); }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { landforms = NoiseLandforms.landforms; IMapChunk mapchunk = chunks[0].MapChunk; IntMap regionMap = mapchunk.MapRegion.LandformMap; // Amount of pixels for each chunk (probably 1, 2, or 4) float chunkPixelSize = regionMap.InnerSize / regionChunkSize; // Adjusted lerp for the noiseWidth float chunkPixelStep = chunkPixelSize / noiseWidth; // Start coordinates for the chunk in the region map float baseX = (chunkX % regionChunkSize) * chunkPixelSize; float baseZ = (chunkZ % regionChunkSize) * chunkPixelSize; LerpedWeightedIndex2DMap landLerpMap = GetOrLoadLerpedLandformMap(chunks[0].MapChunk, chunkX / regionChunkSize, chunkZ / regionChunkSize); // Terrain octaves double[] octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3; double[] octThX0, octThX1, octThX2, octThX3; GetInterpolatedOctaves(landLerpMap[baseX, baseZ], out octNoiseX0, out octThX0); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ], out octNoiseX1, out octThX1); GetInterpolatedOctaves(landLerpMap[baseX, baseZ + chunkPixelSize], out octNoiseX2, out octThX2); GetInterpolatedOctaves(landLerpMap[baseX + chunkPixelSize, baseZ + chunkPixelSize], out octNoiseX3, out octThX3); double[] terrainNoise3d = GetTerrainNoise3D(octNoiseX0, octNoiseX1, octNoiseX2, octNoiseX3, octThX0, octThX1, octThX2, octThX3, chunkX * noiseWidth, 0, chunkZ * noiseWidth); // Store heightmap in the map chunk ushort[] rainheightmap = chunks[0].MapChunk.RainHeightMap; ushort[] terrainheightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; // Terrain thresholds double tnoiseY0; double tnoiseY1; double tnoiseY2; double tnoiseY3; double tnoiseGainY0; double tnoiseGainY1; double tnoiseGainY2; double tnoiseGainY3; double thNoiseX0; double thNoiseX1; double thNoiseGainX0; double thNoiseGainX1; double thNoiseGainZ0; double thNoiseZ0; float[] terrainThresholdsX0 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX1 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX2 = new float[api.WorldManager.MapSizeY]; float[] terrainThresholdsX3 = new float[api.WorldManager.MapSizeY]; for (int xN = 0; xN < noiseWidth; xN++) { for (int zN = 0; zN < noiseWidth; zN++) { // Landform thresholds LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX0); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + zN * chunkPixelStep], terrainThresholdsX1); LoadInterpolatedThresholds(landLerpMap[baseX + xN * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX2); LoadInterpolatedThresholds(landLerpMap[baseX + (xN + 1) * chunkPixelStep, baseZ + (zN + 1) * chunkPixelStep], terrainThresholdsX3); for (int yN = 0; yN < noiseHeight; yN++) { // Terrain noise tnoiseY0 = terrainNoise3d[NoiseIndex3d(xN, yN, zN)]; tnoiseY1 = terrainNoise3d[NoiseIndex3d(xN, yN, zN + 1)]; tnoiseY2 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN)]; tnoiseY3 = terrainNoise3d[NoiseIndex3d(xN + 1, yN, zN + 1)]; tnoiseGainY0 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN)] - tnoiseY0) * lerpDeltaVert; tnoiseGainY1 = (terrainNoise3d[NoiseIndex3d(xN, yN + 1, zN + 1)] - tnoiseY1) * lerpDeltaVert; tnoiseGainY2 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN)] - tnoiseY2) * lerpDeltaVert; tnoiseGainY3 = (terrainNoise3d[NoiseIndex3d(xN + 1, yN + 1, zN + 1)] - tnoiseY3) * lerpDeltaVert; for (int y = 0; y < lerpVer; y++) { int posY = yN * lerpVer + y; int chunkY = posY / chunksize; int localY = posY % chunksize; // For Terrain noise double tnoiseX0 = tnoiseY0; double tnoiseX1 = tnoiseY1; double tnoiseGainX0 = (tnoiseY2 - tnoiseY0) * lerpDeltaHor; double tnoiseGainX1 = (tnoiseY3 - tnoiseY1) * lerpDeltaHor; // Landform thresholds lerp thNoiseX0 = terrainThresholdsX0[posY]; thNoiseX1 = terrainThresholdsX2[posY]; thNoiseGainX0 = (terrainThresholdsX1[posY] - thNoiseX0) * lerpDeltaHor; thNoiseGainX1 = (terrainThresholdsX3[posY] - thNoiseX1) * lerpDeltaHor; for (int x = 0; x < lerpHor; x++) { // For terrain noise double tnoiseZ0 = tnoiseX0; double tnoiseGainZ0 = (tnoiseX1 - tnoiseX0) * lerpDeltaHor; // Landform thNoiseZ0 = thNoiseX0; thNoiseGainZ0 = (thNoiseX1 - thNoiseX0) * lerpDeltaHor; for (int z = 0; z < lerpHor; z++) { int lX = xN * lerpHor + x; int lZ = zN * lerpHor + z; int mapIndex = ChunkIndex2d(lX, lZ); int chunkIndex = ChunkIndex3d(lX, localY, lZ); chunks[chunkY].Blocks[chunkIndex] = 0; if (posY == 0) { chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.mantleBlockId; continue; } if (tnoiseZ0 > thNoiseZ0) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.defaultRockId; } else { if (posY < TerraGenConfig.seaLevel) { terrainheightmap[mapIndex] = rainheightmap[mapIndex] = (ushort)Math.Max(rainheightmap[mapIndex], posY); chunks[chunkY].Blocks[chunkIndex] = GlobalConfig.waterBlockId; } else { chunks[chunkY].Blocks[chunkIndex] = 0; } } tnoiseZ0 += tnoiseGainZ0; thNoiseZ0 += thNoiseGainZ0; } tnoiseX0 += tnoiseGainX0; tnoiseX1 += tnoiseGainX1; thNoiseX0 += thNoiseGainX0; thNoiseX1 += thNoiseGainX1; } tnoiseY0 += tnoiseGainY0; tnoiseY1 += tnoiseGainY1; tnoiseY2 += tnoiseGainY2; tnoiseY3 += tnoiseGainY3; } } } } int ymax = 0; for (int i = 0; i < rainheightmap.Length; i++) { ymax = Math.Max(ymax, rainheightmap[i]); } chunks[0].MapChunk.YMax = (ushort)ymax; }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; int climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); int climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); int climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); int climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); int climateMid = GameMath.BiLerpRgbColor(0.5f, 0.5f, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); // 16-23 bits = Red = temperature // 8-15 bits = Green = rain // 0-7 bits = Blue = humidity int rain = (climateMid >> 8) & 0xff; int humidity = climateMid & 0xff; int temp = (climateMid >> 16) & 0xff; int quantityRivulets = (int)(80 * (rain + humidity) / 255f) * (api.WorldManager.MapSizeY / chunksize) - Math.Max(0, 100 - temp); int fx, fy, fz; while (quantityRivulets-- > 0) { int dx = 1 + rnd.Next(chunksize - 2); int y = 1 + rnd.Next(api.WorldManager.MapSizeY - 2); int dz = 1 + rnd.Next(chunksize - 2); int quantitySolid = 0; int quantityAir = 0; for (int i = 0; i < BlockFacing.ALLFACES.Length; i++) { BlockFacing facing = BlockFacing.ALLFACES[i]; fx = dx + facing.Normali.X; fy = y + facing.Normali.Y; fz = dz + facing.Normali.Z; Block block = api.World.Blocks[ chunks[fy / chunksize].Blocks[(chunksize * (fy % chunksize) + fz) * chunksize + fx] ]; bool solid = block.BlockMaterial == EnumBlockMaterial.Stone; quantitySolid += solid ? 1 : 0; quantityAir += (block.BlockMaterial == EnumBlockMaterial.Air) ? 1 : 0; if (!solid && facing == BlockFacing.UP) { quantitySolid = 0; } } if (quantitySolid != 5 || quantityAir != 1) { continue; } chunks[y / chunksize].Blocks[(chunksize * (y % chunksize) + dz) * chunksize + dx] = y < 24 ? GlobalConfig.lavaBlockId : GlobalConfig.waterBlockId; BlockPos pos = new BlockPos(chunkX * chunksize + dx, y, chunkZ * chunksize + dz); blockAccessor.ScheduleBlockUpdate(pos); } }
public LazySymbolMap(IntMap intMap, Value [] values) { _intMap = intMap; _values = values; }
internal void CreatePage(int i, IntMap intMap) { if(this[i] == Plane.EmptyPage) { Page page = new Page(); this[i] = page; } }
public HierarchyView(UIView[] views, TreeViewState state) : base(state) { this.views = views; m_ViewState = new IntMap <ViewState>(); needsReload = true; }
private void OnChunkColumnGen(IServerChunk[] chunks, int chunkX, int chunkZ) { if (!TerraGenConfig.GenerateStructures) { return; } IMapRegion region = chunks[0].MapChunk.MapRegion; IntMap forestMap = region.ForestMap; IntMap climateMap = region.ClimateMap; int rlX = chunkX % regionChunkSize; int rlZ = chunkZ % regionChunkSize; // A region has 16 chunks // Size of the forest map is RegionSize / TerraGenConfig.forestMapScale => 32*16 / 32 = 16 pixel // rlX, rlZ goes from 0..16 pixel // facF = 16/16 = 1 // Get 4 pixels for chunkx, chunkz, chunkx+1 and chunkz+1 inside the map float facF = (float)forestMap.InnerSize / regionChunkSize; forestUpLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF)); forestUpRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF)); forestBotLeft = forestMap.GetUnpaddedInt((int)(rlX * facF), (int)(rlZ * facF + facF)); forestBotRight = forestMap.GetUnpaddedInt((int)(rlX * facF + facF), (int)(rlZ * facF + facF)); float facC = (float)climateMap.InnerSize / regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * facC), (int)(rlZ * facC + facC)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * facC + facC), (int)(rlZ * facC + facC)); heightmap = chunks[0].MapChunk.WorldGenTerrainHeightMap; BlockPos pos = new BlockPos(); for (int i = 0; i < scfg.Structures.Length; i++) { WorldGenStructure struc = scfg.Structures[i]; float chance = struc.Chance * scfg.ChanceMultiplier; while (chance-- > rnd.NextDouble()) { int dx = rnd.Next(chunksize); int dz = rnd.Next(chunksize); int ySurface = heightmap[dz * chunksize + dx]; if (ySurface <= 0 || ySurface >= worldheight - 15) { continue; } if (struc.Placement == EnumStructurePlacement.Underground) { if (struc.Depth != null) { pos.Set(chunkX * chunksize + dx, ySurface - (int)struc.Depth.nextFloat(), chunkZ * chunksize + dz); } else { pos.Set(chunkX * chunksize + dx, 8 + rnd.Next(ySurface - 8 - 5), chunkZ * chunksize + dz); } } else { pos.Set(chunkX * chunksize + dx, ySurface, chunkZ * chunksize + dz); } struc.TryGenerate(worldgenBlockAccessor, api.World, pos, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); } } }
public void TryPlaceLakeAt(int dx, int dz, int chunkX, int chunkZ, ushort[] heightmap, int depth = 0) { searchPositionsDeltas.Clear(); lakePositions.Clear(); // Clear Array for (int i = 0; i < didCheckPosition.Length; i++) { didCheckPosition[i] = false; } lakeYPos = heightmap[dz * chunksize + dx] + 1; if (lakeYPos <= 0 || lakeYPos >= mapheight - 1) { return; } int basePosX = chunkX * chunksize; int basePosZ = chunkZ * chunksize; Vec2i tmp = new Vec2i(); searchPositionsDeltas.Enqueue(new Vec2i(dx, dz)); lakePositions.Enqueue(new Vec2i(basePosX + dx, basePosZ + dz)); didCheckPosition[(dz + mapOffset) * searchSize + dx + mapOffset] = true; while (searchPositionsDeltas.Count > 0) { Vec2i p = searchPositionsDeltas.Dequeue(); foreach (BlockFacing facing in BlockFacing.HORIZONTALS) { ndx = p.X + facing.Normali.X; ndz = p.Y + facing.Normali.Z; tmp.Set(chunkX * chunksize + ndx, chunkZ * chunksize + ndz); Block belowBlock = blockAccessor.GetBlock(tmp.X, lakeYPos - 1, tmp.Y); bool inBoundary = ndx > minBoundary && ndz > minBoundary && ndx < maxBoundary && ndz < maxBoundary; // Only continue when within our 3x3 chunk search area and having a more or less solid block below (or water) if (inBoundary && (belowBlock.Replaceable < 6000 || belowBlock.BlockId == GlobalConfig.waterBlockId)) { int arrayIndex = (ndz + mapOffset) * searchSize + ndx + mapOffset; // Already checked or did we reach a lake border? if (!didCheckPosition[arrayIndex] && blockAccessor.GetBlock(tmp.X, lakeYPos, tmp.Y).Replaceable >= 6000) { searchPositionsDeltas.Enqueue(new Vec2i(ndx, ndz)); lakePositions.Enqueue(tmp.Copy()); didCheckPosition[arrayIndex] = true; } } else { lakePositions.Clear(); searchPositionsDeltas.Clear(); return; } } } if (lakePositions.Count == 0) { return; } int curChunkX, curChunkZ; int prevChunkX = -1, prevChunkZ = -1; int regionChunkSize = api.WorldManager.RegionSize / chunksize; IMapChunk mapchunk = null; IServerChunk chunk = null; IServerChunk chunkOneBlockBelow = null; int ly = GameMath.Mod(lakeYPos, chunksize); bool extraLakeDepth = rand.NextDouble() > 0.5; bool withSeabed = extraLakeDepth || lakePositions.Count > 16; foreach (Vec2i p in lakePositions) { curChunkX = p.X / chunksize; curChunkZ = p.Y / chunksize; int lx = GameMath.Mod(p.X, chunksize); int lz = GameMath.Mod(p.Y, chunksize); // Get correct chunk and correct climate data if we don't have it already if (curChunkX != prevChunkX || curChunkZ != prevChunkZ) { chunk = ((IServerChunk)blockAccessor.GetChunk(curChunkX, lakeYPos / chunksize, curChunkZ)); chunk.Unpack(); if (ly == 0) { chunkOneBlockBelow = ((IServerChunk)blockAccessor.GetChunk(curChunkX, (lakeYPos - 1) / chunksize, curChunkZ)); chunkOneBlockBelow.Unpack(); } else { chunkOneBlockBelow = chunk; } mapchunk = chunk.MapChunk; IntMap climateMap = mapchunk.MapRegion.ClimateMap; float fac = (float)climateMap.InnerSize / regionChunkSize; int rlX = curChunkX % regionChunkSize; int rlZ = curChunkZ % regionChunkSize; climateUpLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac)); climateUpRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac)); climateBotLeft = climateMap.GetUnpaddedInt((int)(rlX * fac), (int)(rlZ * fac + fac)); climateBotRight = climateMap.GetUnpaddedInt((int)(rlX * fac + fac), (int)(rlZ * fac + fac)); prevChunkX = curChunkX; prevChunkZ = curChunkZ; } // Raise heightmap by 1 mapchunk.RainHeightMap[lz * chunksize + lx] = (ushort)lakeYPos; // Identify correct climate at this position int climate = GameMath.BiLerpRgbColor((float)lx / chunksize, (float)lz / chunksize, climateUpLeft, climateUpRight, climateBotLeft, climateBotRight); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat((climate >> 16) & 0xff, lakeYPos - TerraGenConfig.seaLevel); // 1. Place water or ice block chunk.Blocks[(ly * chunksize + lz) * chunksize + lx] = temp < -5 ? GlobalConfig.lakeIceBlockId : GlobalConfig.waterBlockId; // 2. Let's make a nice muddy gravely sea bed if (!withSeabed) { continue; } // Need to check the block below first int index = ly == 0 ? ((31 * chunksize + lz) * chunksize + lx) : (((ly - 1) * chunksize + lz) * chunksize + lx) ; Block belowBlock = api.World.Blocks[chunkOneBlockBelow.Blocks[index]]; // Water below? Seabed already placed if (belowBlock.IsLiquid()) { continue; } float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, lakeYPos) / 255f; ushort rockBlockId = mapchunk.TopRockIdMap[lz * chunksize + lx]; if (rockBlockId == 0) { continue; } for (int i = 0; i < lakebedLayerConfig.BlockCodeByMin.Length; i++) { if (lakebedLayerConfig.BlockCodeByMin[i].Suitable(temp, rainRel, (float)lakeYPos / mapheight, rand)) { chunkOneBlockBelow.Blocks[index] = lakebedLayerConfig.BlockCodeByMin[i].GetBlockForMotherRock(rockBlockId); break; } } } if (lakePositions.Count > 0 && extraLakeDepth) { TryPlaceLakeAt(dx, dz, chunkX, chunkZ, heightmap, depth + 1); } }
void ReadPos(IServerPlayer player, CmdArgs arguments) { if (arguments.Length < 2) { player.SendMessage(groupId, "/wgen pos [gprov|landform|climate|height]", EnumChatType.CommandError); return; } int chunkSize = api.WorldManager.ChunkSize; BlockPos pos = player.Entity.Pos.AsBlockPos; IServerChunk serverchunk = api.WorldManager.GetChunk(pos); if (serverchunk == null) { player.SendMessage(groupId, "Can check here, beyond chunk boundaries!", EnumChatType.CommandError); return; } IMapRegion mapRegion = serverchunk.MapChunk.MapRegion; int regionChunkSize = api.WorldManager.RegionSize / chunkSize; int lx = pos.X % chunkSize; int lz = pos.Z % chunkSize; int chunkX = pos.X / chunkSize; int chunkZ = pos.Z / chunkSize; int regionX = pos.X / regionSize; int regionZ = pos.Z / regionSize; switch (arguments[1]) { case "height": { string str = string.Format("Rain y={0}, Worldgen terrain y={1}", serverchunk.MapChunk.RainHeightMap[lz * chunkSize + lx], serverchunk.MapChunk.WorldGenTerrainHeightMap[lz * chunkSize + lx]); player.SendMessage(groupId, str, EnumChatType.CommandSuccess); } break; case "gprov": { int noiseSizeGeoProv = mapRegion.GeologicProvinceMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeGeoProv; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeGeoProv; GeologicProvinceVariant[] provincesByIndex = NoiseGeoProvince.provinces.Variants; IntMap intmap = mapRegion.GeologicProvinceMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.GeologicProvinceMap.Size, TerraGenConfig.geoProvSmoothingRadius); WeightedIndex[] indices = map[intmap.TopLeftPadding + posXInRegion, intmap.TopLeftPadding + posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.weight).ToString("#.#") + "% " + provincesByIndex[windex.index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "landform": { int noiseSizeLandform = mapRegion.LandformMap.InnerSize; float posXInRegion = ((float)pos.X / regionSize - pos.X / regionSize) * noiseSizeLandform; float posZInRegion = ((float)pos.Z / regionSize - pos.Z / regionSize) * noiseSizeLandform; LandformVariant[] landforms = NoiseLandforms.landforms.LandFormsByIndex; IntMap intmap = mapRegion.LandformMap; LerpedWeightedIndex2DMap map = new LerpedWeightedIndex2DMap(intmap.Data, mapRegion.LandformMap.Size, TerraGenConfig.landFormSmothingRadius); WeightedIndex[] indices = map[intmap.TopLeftPadding + posXInRegion, intmap.TopLeftPadding + posZInRegion]; string text = ""; foreach (WeightedIndex windex in indices) { if (text.Length > 0) { text += ", "; } text += (100 * windex.weight).ToString("#.#") + "% " + landforms[windex.index].Code; } player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } case "climate": { ClimateCondition climate = api.World.BlockAccessor.GetClimateAt(pos); string text = string.Format("Temperature: {0}°, Rainfall: {1}%, Fertility: {2}%, Forest: {3}%, Shrub: {4}%, Sealevel dist: {5}%", climate.Temperature.ToString("0.#"), (int)(climate.Rainfall * 100f), (int)(climate.Fertility * 100f), (int)(climate.ForestDensity * 100f), (int)(climate.ShrubDensity * 100f), (int)(100f * pos.Y / 255f)); player.SendMessage(groupId, text, EnumChatType.CommandSuccess); break; } } }
void TestMap(IServerPlayer player, CmdArgs arguments) { if (arguments.Length < 2) { player.SendMessage(groupId, "/wgen testmap [climate|forest|wind|gprov|landform|ore]", EnumChatType.CommandError); return; } Random rnd = new Random(); long seed = rnd.Next(); switch (arguments[1]) { case "climate": { NoiseBase.Debug = true; NoiseClimate noiseClimate = new NoiseClimate(seed); MapLayerBase climate = GenMaps.GetClimateMap(seed, noiseClimate); player.SendMessage(groupId, "Climate map generated", EnumChatType.CommandSuccess); } break; case "forest": { NoiseBase.Debug = false; NoiseClimate noiseClimate = new NoiseClimate(seed); MapLayerBase climate = GenMaps.GetClimateMap(seed, noiseClimate); MapLayerBase forest = GenMaps.GetForestMap(seed + 1, TerraGenConfig.forestMapScale); IntMap climateMap = new IntMap() { Data = climate.GenLayer(0, 0, 512, 512), Size = 512 }; forest.SetInputMap(climateMap, new IntMap() { Size = 512 }); NoiseBase.Debug = true; forest.DebugDrawBitmap(1, 0, 0, "Forest 1 - Forest"); player.SendMessage(groupId, "Forest map generated", EnumChatType.CommandSuccess); } break; case "ore": { NoiseBase.Debug = false; NoiseOre noiseOre = new NoiseOre(seed); MapLayerBase climate = GenMaps.GetOreMap(seed, noiseOre); NoiseBase.Debug = true; climate.DebugDrawBitmap(0, 0, 0, 1024, "Ore 1 - Ore"); player.SendMessage(groupId, "ore map generated", EnumChatType.CommandSuccess); } break; case "wind": NoiseBase.Debug = true; NoiseBase wind = GenMaps.GetDebugWindMap(seed); player.SendMessage(groupId, "Wind map generated", EnumChatType.CommandSuccess); break; case "gprov": NoiseBase.Debug = true; MapLayerBase provinces = GenMaps.GetGeologicProvinceMap(seed, api); player.SendMessage(groupId, "Province map generated", EnumChatType.CommandSuccess); break; case "landform": { NoiseBase.Debug = true; NoiseClimate noiseClimate = new NoiseClimate(seed); MapLayerBase landforms = GenMaps.GetLandformMap(seed + 1, noiseClimate, api); player.SendMessage(groupId, "Landforms map generated", EnumChatType.CommandSuccess); } break; default: player.SendMessage(groupId, "/wgen testmap [climate|forest|wind|gprov]", EnumChatType.CommandError); break; } NoiseBase.Debug = false; }
LerpedWeightedIndex2DMap CreateLerpedProvinceMap(IntMap geoMap, int regionX, int regionZ) { int index2d = regionZ * regionMapSize + regionX; return(ProvinceMapByRegion[index2d] = new LerpedWeightedIndex2DMap(geoMap.Data, geoMap.Size, TerraGenConfig.geoProvSmoothingRadius, geoMap.TopLeftPadding, geoMap.BottomRightPadding)); }
public void SetInputMap(IntMap inputMap, IntMap outputMap) { this.inputMap = inputMap; this.outputMap = outputMap; }
public StyleSystem() { this.m_ChangeSets = new IntMap <ChangeSet>(); }
private void OnChunkColumnGeneration(IServerChunk[] chunks, int chunkX, int chunkZ, ITreeAttribute chunkGenParams = null) { rnd.InitPositionSeed(chunkX, chunkZ); IntMap forestMap = chunks[0].MapChunk.MapRegion.ForestMap; IntMap climateMap = chunks[0].MapChunk.MapRegion.ClimateMap; IntMap beachMap = chunks[0].MapChunk.MapRegion.BeachMap; ushort[] heightMap = chunks[0].MapChunk.RainHeightMap; int regionChunkSize = api.WorldManager.RegionSize / chunksize; //fetch the region coordinates int rdx = chunkX % regionChunkSize; int rdz = chunkZ % regionChunkSize; // Amount of data points per chunk float climateStep = (float)climateMap.InnerSize / regionChunkSize; float forestStep = (float)forestMap.InnerSize / regionChunkSize; float beachStep = (float)beachMap.InnerSize / regionChunkSize; // Retrieves the map data on the chunk edges int forestUpLeft = forestMap.GetUnpaddedInt((int)(rdx * forestStep), (int)(rdz * forestStep)); int forestUpRight = forestMap.GetUnpaddedInt((int)(rdx * forestStep + forestStep), (int)(rdz * forestStep)); int forestBotLeft = forestMap.GetUnpaddedInt((int)(rdx * forestStep), (int)(rdz * forestStep + forestStep)); int forestBotRight = forestMap.GetUnpaddedInt((int)(rdx * forestStep + forestStep), (int)(rdz * forestStep + forestStep)); int beachUpLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep)); int beachUpRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep)); int beachBotLeft = beachMap.GetUnpaddedInt((int)(rdx * beachStep), (int)(rdz * beachStep + beachStep)); int beachBotRight = beachMap.GetUnpaddedInt((int)(rdx * beachStep + beachStep), (int)(rdz * beachStep + beachStep)); // increasing x -> left to right // increasing z -> top to bottom float transitionSize = blockLayerConfig.blockLayerTransitionSize; for (int x = 0; x < chunksize; x++) { for (int z = 0; z < chunksize; z++) { // Some weird randomnes stuff to hide fundamental bugs in the climate transition system :D T_T (maybe not bugs but just fundamental shortcomings of using lerp on a very low resolution map) float distx = (float)distort2dx.Noise(chunkX * chunksize + x, chunkZ * chunksize + z); float distz = (float)distort2dz.Noise(chunkX * chunksize + x, chunkZ * chunksize + z); double posRand = (double)GameMath.MurmurHash3(x + chunkX * chunksize, 1, z + chunkZ * chunksize) / int.MaxValue; double transitionRand = (posRand + 1) * transitionSize; int posY = heightMap[z * chunksize + x]; int climate = climateMap.GetUnpaddedColorLerped( Math.Abs(rdx * climateStep + climateStep * (float)(x + distx) / chunksize), Math.Abs(rdz * climateStep + climateStep * (float)(z + distz) / chunksize) ); int tempUnscaled = (climate >> 16) & 0xff; int rnd = (int)(distx / 5); float temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel + rnd); float rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY + rnd) / 255f; float forestRel = GameMath.BiLerp(forestUpLeft, forestUpRight, forestBotLeft, forestBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; float beachRel = GameMath.BiLerp(beachUpLeft, beachUpRight, beachBotLeft, beachBotRight, (float)x / chunksize, (float)z / chunksize) / 255f; //api.World.Logger.Notification(x.ToString() + " " + z.ToString() + " temp: " + tempUnscaled.ToString() + " distx" + distx.ToString() + " distz" + distz.ToString()); int prevY = posY; posY = PutLayers(transitionRand, x, posY, z, chunks, rainRel, temp, tempUnscaled, heightMap); int blockID = chunks[0].MapChunk.TopRockIdMap[z * chunksize + x]; GenBeach(x, prevY, z, chunks, rainRel, temp, beachRel, blockID); PlaceTallGrass(x, prevY, z, chunks, rainRel, temp, forestRel); // Try again to put layers if above sealevel and we found over 10 air blocks int foundAir = 0; while (posY >= TerraGenConfig.seaLevel - 1) { int chunkY = posY / chunksize; int lY = posY % chunksize; int index3d = (chunksize * lY + z) * chunksize + x; int blockId = chunks[chunkY].Blocks[index3d]; if (blockId == 0) { foundAir++; } else { if (foundAir >= 8) { temp = TerraGenConfig.GetScaledAdjustedTemperatureFloat(tempUnscaled, posY - TerraGenConfig.seaLevel); rainRel = TerraGenConfig.GetRainFall((climate >> 8) & 0xff, posY) / 255f; //PutLayers(transitionRand, x, posY, z, chunks, rainRel, temp, tempUnscaled, null); break; } else { foundAir = 0; } } posY--; } } } }
/// <summary> /// Cache index to the list of scaled shapeable typeface /// </summary> private void CacheScaledTypefaceMap( CharacterBufferRange unicodeString, CultureInfo culture, CultureInfo digitCulture, SpanVector scaledTypefaceSpans, ref SpanVector<int> cachedScaledTypefaceIndexSpans, int ichItem ) { IntMap map; if (!_intMaps.TryGetValue(culture, out map)) { map = new IntMap(); _intMaps.Add(culture, map); } DigitMap digitMap = new DigitMap(digitCulture); SpanRider typefaceSpanRider = new SpanRider(scaledTypefaceSpans); int ich = 0; while(ich < unicodeString.Length) { typefaceSpanRider.At(ich); int cch = Math.Min(unicodeString.Length - ich, typefaceSpanRider.Length); int index = IndexOfScaledTypeface((ScaledShapeTypeface)typefaceSpanRider.CurrentElement); Debug.Assert(index >= 0, "Invalid scaled shapeable typeface index spans"); cachedScaledTypefaceIndexSpans.Set(ichItem + ich, cch, index); // we keep index + 1 in the map, so that we leave map entry zero // to indicate uninitialized entry. index++; int sizeofChar; for (int c = 0; c < cch; c += sizeofChar) { int ch = digitMap[ Classification.UnicodeScalar( new CharacterBufferRange(unicodeString, ich + c, unicodeString.Length - ich - c), out sizeofChar ) ]; // only cache typeface map index for base characters if(!Classification.IsCombining(ch) && !Classification.IsJoiner(ch)) { // Dump values of local variables when the condition fails for better debuggability. // We use "if" to avoid the expensive string.Format() in normal case. if (map[ch] != 0 && map[ch] != index) { Invariant.Assert( false, string.Format( CultureInfo.InvariantCulture, "shapeable cache stores conflicting info, ch = {0}, map[ch] = {1}, index = {2}", ch, map[ch], index ) ); } map[ch] = (ushort)index; } } ich += cch; } }
private static int ApplyIntMap(IntMap f, int x) { return(f(x)); }