fixed lake and river merging

This commit is contained in:
Grimsace
2026-01-30 10:55:15 -06:00
parent 30379f53f8
commit 1b286bfca4
2 changed files with 56 additions and 15 deletions
+16 -6
View File
@@ -100,10 +100,16 @@ func main() {
if canvasImg.Image == nil || heightmapImg.Image == nil {
// Initial image generation
noiseImg := GenerateHeightmap(settings.Width, settings.Height, int(settings.Detail), 100.0, settings.Seed)
lakeImage, lakePixels := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
riverImage, riverPixels := GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakePixels, settings.Seed)
lakeImage, lakes := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
riverImage, riverPixels := GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, settings.Seed)
finalImage := riverImage.(*image.RGBA)
allWaterPixels := append(lakePixels, riverPixels...)
var flatLakePixels []image.Point
for _, lake := range lakes {
flatLakePixels = append(flatLakePixels, lake...)
}
allWaterPixels := append(flatLakePixels, riverPixels...)
GenerateTrees(finalImage, allWaterPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, settings.Seed)
darkenedHeightmap := DarkenLakeAreas(noiseImg, allWaterPixels)
compositeImg := ApplyRoughness(darkenedHeightmap, settings.Roughness)
@@ -267,16 +273,20 @@ func main() {
currentStep++
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Lakes", currentStep, steps))
progressBar.SetValue(float64(currentStep) / float64(steps))
lakeImage, lakePixels := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
lakeImage, lakes := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
// Step 3: Generating Rivers
currentStep++
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Rivers", currentStep, steps))
progressBar.SetValue(float64(currentStep) / float64(steps))
riverImage, riverPixels := GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakePixels, settings.Seed)
riverImage, riverPixels := GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, settings.Seed)
finalImage := riverImage.(*image.RGBA)
allWaterPixels := append(lakePixels, riverPixels...)
var flatLakePixels []image.Point
for _, lake := range lakes {
flatLakePixels = append(flatLakePixels, lake...)
}
allWaterPixels := append(flatLakePixels, riverPixels...)
// Step 4: Darkening Water Areas
currentStep++
+40 -9
View File
@@ -45,8 +45,7 @@ func (pq *priorityQueue) Pop() interface{} {
return item
}
// GenerateLakes creates a specific number of lakes by dividing the image into chunks and placing one lake per chunk.
func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper float64, heightmap image.Image, seed int64) (image.Image, []image.Point) {
func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper float64, heightmap image.Image, seed int64) (image.Image, [][]image.Point) {
canvas := image.NewRGBA(image.Rect(0, 0, width, height))
draw.Draw(canvas, canvas.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
@@ -54,7 +53,7 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
return canvas, nil
}
var allLakePixels []image.Point
var allLakes [][]image.Point
randSrc := rand.New(rand.NewSource(seed))
// 1. Divide the image into a grid
@@ -86,6 +85,8 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
break
}
var currentLake []image.Point
// Each lake gets a random size within the defined range
lakeSize := lakeSizeLower
if lakeSizeUpper > lakeSizeLower {
@@ -147,7 +148,7 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
// The pixel is valid, claim it.
canvas.Set(current.point.X, current.point.Y, color.RGBA{R: 0, G: 0, B: 255, A: 255})
allLakePixels = append(allLakePixels, current.point)
currentLake = append(currentLake, current.point)
lakeCount++
// Add neighbors, constrained to the chunk rectangle
@@ -170,9 +171,12 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
}
}
}
if len(currentLake) > 0 {
allLakes = append(allLakes, currentLake)
}
}
return canvas, allLakePixels
return canvas, allLakes
}
type River struct {
@@ -181,7 +185,7 @@ type River struct {
Points []image.Point
}
func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness float64, inputImage image.Image, lakePixels []image.Point, seed int64) (image.Image, []image.Point) {
func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness float64, inputImage image.Image, lakes [][]image.Point, seed int64) (image.Image, []image.Point) {
if numRivers == 0 {
return inputImage, nil
}
@@ -197,8 +201,12 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
avgDim := float64(width+height) / 2.0
isWater := make(map[image.Point]bool)
for _, p := range lakePixels {
isWater[p] = true
lakePixelMap := make(map[image.Point]int)
for i, lake := range lakes {
for _, p := range lake {
isWater[p] = true
lakePixelMap[p] = i
}
}
rivers := make([]River, numRivers)
@@ -232,7 +240,14 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
for _, p := range path {
if isWater[p] {
r.End = p
if lakeIndex, isLake := lakePixelMap[p]; isLake {
// Intersection is with a lake, find its center
lakeCenter := findCenter(lakes[lakeIndex])
r.End = lakeCenter
} else {
// Intersection is with another river
r.End = p
}
path = calculatePath(r.Start, r.End, curvyness/100.0, avgDim, randSrc, numControlPoints)
break
}
@@ -242,6 +257,7 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
radius := riverWidthPx / 2.0
for _, p := range path {
// When drawing river pixels, add them to isWater to detect river-river intersections
drawCircle(canvas, p, radius, color.RGBA{R: 0, G: 0, B: 255, A: 255}, &allRiverPixels, isWater)
}
r.Points = path
@@ -250,6 +266,21 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
return canvas, allRiverPixels
}
func findCenter(pixels []image.Point) image.Point {
if len(pixels) == 0 {
return image.Point{}
}
var sumX, sumY int
for _, p := range pixels {
sumX += p.X
sumY += p.Y
}
return image.Point{
X: sumX / len(pixels),
Y: sumY / len(pixels),
}
}
func getPointOnEdge(width, height, edge int, randSrc *rand.Rand) image.Point {
switch edge {
case 0: // Top