public bool TryGetValue(int x, int z, out HeightMapInfo[] heights, out int heightIndex) { int fx = x >> 8; int fz = z >> 8; heightIndex = ((z - (fz << 8)) << 8) + (x - (fx << 8)); uint key = (uint)(((fz + 1024) << 16) + (fx + 1024)); if (key == lastKey && lastSector != null) { heights = lastSector; } else if (!heightSectors.TryGetValue(key, out heights)) { heights = new HeightMapInfo[65536]; heightSectors.Add(key, heights); } lastSector = heights; lastKey = key; return(heights [heightIndex].groundLevel != 0); }
/// <summary> /// Paints the terrain inside the chunk defined by its central "position" /// </summary> /// <returns><c>true</c>, if terrain was painted, <c>false</c> otherwise.</returns> public override bool PaintChunk(VoxelChunk chunk) { Vector3 position = chunk.position; if (position.y + VoxelPlayEnvironment.CHUNK_HALF_SIZE < minHeight) { chunk.isAboveSurface = false; return(false); } int bedrockRow = -1; if ((object)bedrockVoxel != null && position.y < minHeight + VoxelPlayEnvironment.CHUNK_HALF_SIZE) { bedrockRow = (int)(minHeight - (position.y - VoxelPlayEnvironment.CHUNK_HALF_SIZE) + 1) * ONE_Y_ROW; } position.x -= VoxelPlayEnvironment.CHUNK_HALF_SIZE; position.y -= VoxelPlayEnvironment.CHUNK_HALF_SIZE; position.z -= VoxelPlayEnvironment.CHUNK_HALF_SIZE; Vector3 pos; int waterLevel = env.waterLevel > 0 ? env.waterLevel : -1; Voxel[] voxels = chunk.voxels; bool hasContent = false; bool isAboveSurface = false; for (int z = 0; z < VoxelPlayEnvironment.CHUNK_SIZE; z++) { pos.z = position.z + z; int arrayZIndex = z * ONE_Z_ROW; for (int x = 0; x < VoxelPlayEnvironment.CHUNK_SIZE; x++) { pos.x = position.x + x; HeightMapInfo heightMapInfo = env.GetHeightMapInfoFast(pos.x, pos.z); float groundLevel = heightMapInfo.groundLevel; float surfaceLevel = waterLevel > groundLevel ? waterLevel : groundLevel; if (surfaceLevel < position.y) { // position is above terrain or water isAboveSurface = true; continue; } int hindex = GetHeightIndex(pos.x, pos.z); if (hindex < 0) { continue; } VoxelDefinition vd = heights [hindex].terrainVoxelTop; if ((object)vd == null) { continue; } int y = (int)(surfaceLevel - position.y); if (y >= VoxelPlayEnvironment.CHUNK_SIZE) { y = (VoxelPlayEnvironment.CHUNK_SIZE - 1); } pos.y = position.y + y; // Place voxels int voxelIndex = y * ONE_Y_ROW + arrayZIndex + x; if (pos.y > groundLevel) { // water above terrain if (pos.y == surfaceLevel) { isAboveSurface = true; } while (pos.y > groundLevel && voxelIndex >= 0) { voxels [voxelIndex].Set(waterVoxel); voxelIndex -= ONE_Y_ROW; pos.y--; } } else if (pos.y == groundLevel) { isAboveSurface = true; if (voxels [voxelIndex].hasContent == 0) { // surface => draw voxel top, vegetation and trees voxels [voxelIndex].Set(vd); #if UNITY_EDITOR if (!env.draftModeActive) { #endif // Check tree probability if (pos.y > waterLevel) { ModelDefinition treeModel = heights [hindex].treeModel; if (env.enableTrees && treeModel != null) { env.RequestTreeCreation(chunk, pos, treeModel); } else if (env.enableVegetation) { VoxelDefinition vegetation = heights [hindex].vegetationVoxel; if (vegetation != null) { if (voxelIndex >= (VoxelPlayEnvironment.CHUNK_SIZE - 1) * ONE_Y_ROW) { env.RequestVegetationCreation(chunk.top, voxelIndex - ONE_Y_ROW * (VoxelPlayEnvironment.CHUNK_SIZE - 1), vegetation); } else { voxels [voxelIndex + ONE_Y_ROW].Set(vegetation); } env.vegetationCreated++; } } } #if UNITY_EDITOR } #endif } voxelIndex -= ONE_Y_ROW; } // Continue filling down vd = heights [hindex].terrainVoxelDirt; while (voxelIndex > bedrockRow) { if (voxels [voxelIndex].hasContent == 0) { voxels [voxelIndex].SetFastOpaque(vd); } voxelIndex -= ONE_Y_ROW; } if (bedrockRow >= 0) { voxels [voxelIndex].SetFastOpaque(bedrockVoxel); } hasContent = true; } } chunk.isAboveSurface = isAboveSurface; return(hasContent); }
void RefreshBiomeTexture() { if (biomeTex == null || biomeTex.width != mapResolution) { biomeTex = new Texture2D(mapResolution, mapResolution, TextureFormat.ARGB32, false); } int width = biomeTex.width; int height = biomeTex.height; Color[] colors = new Color[width * height]; if (env == null || tg == null) { colors.Fill <Color> (new Color(0, 0.5f, 0, 0.5f)); } else { env.SetBiomeDefaultColors(false); colors.Fill <Color> (Misc.colorTransparent); // reset biome stats for (int k = 0; k < world.biomes.Length; k++) { if (world.biomes [k] != null) { world.biomes [k].biomeMapOccurrences = 0; } } // draw biome colors for (int j = 0; j < height; j++) { float z = (maxZ - minZ) * (float)j / height + minZ; int jj = j * width; for (int k = 0; k < width; k++) { float x = (maxX - minX) * (float)k / width + minX; HeightMapInfo info = env.GetTerrainInfo(x, z); if (info.groundLevel <= tg.waterLevel) { colors [jj + k] = waterColor; } else { BiomeDefinition biome = info.biome; if (biome == null) { continue; } biome.biomeMapOccurrences++; if (biome.showInBiomeMap) { colors [jj + k] = biome.biomeMapColor; } } } } int gridCount = (int)((maxZ - minZ) / gridStep); Color gridColor = new Color(64, 64, 64, 0.2f); // draw horizontal grid lines for (int j = 0; j <= gridCount; j++) { int y = (int)((height - 1f) * j / gridCount); for (int k = 0; k < width; k++) { colors [y * width + k] = gridColor; } } gridCount = (int)((maxX - minX) / gridStep); // draw vertical grid lines for (int j = 0; j <= gridCount; j++) { int x = (int)((width - 1f) * j / gridCount); for (int k = 0; k < height; k++) { colors [k * width + x] = gridColor; } } } biomeTex.SetPixels(colors); biomeTex.Apply(); }