fixed lake and river merging
This commit is contained in:
@@ -100,10 +100,16 @@ func main() {
|
|||||||
if canvasImg.Image == nil || heightmapImg.Image == nil {
|
if canvasImg.Image == nil || heightmapImg.Image == nil {
|
||||||
// Initial image generation
|
// Initial image generation
|
||||||
noiseImg := GenerateHeightmap(settings.Width, settings.Height, int(settings.Detail), 100.0, settings.Seed)
|
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)
|
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, 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)
|
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)
|
GenerateTrees(finalImage, allWaterPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, settings.Seed)
|
||||||
darkenedHeightmap := DarkenLakeAreas(noiseImg, allWaterPixels)
|
darkenedHeightmap := DarkenLakeAreas(noiseImg, allWaterPixels)
|
||||||
compositeImg := ApplyRoughness(darkenedHeightmap, settings.Roughness)
|
compositeImg := ApplyRoughness(darkenedHeightmap, settings.Roughness)
|
||||||
@@ -267,16 +273,20 @@ func main() {
|
|||||||
currentStep++
|
currentStep++
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Lakes", currentStep, steps))
|
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Lakes", currentStep, steps))
|
||||||
progressBar.SetValue(float64(currentStep) / float64(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
|
// Step 3: Generating Rivers
|
||||||
currentStep++
|
currentStep++
|
||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Rivers", currentStep, steps))
|
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Rivers", currentStep, steps))
|
||||||
progressBar.SetValue(float64(currentStep) / float64(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)
|
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
|
// Step 4: Darkening Water Areas
|
||||||
currentStep++
|
currentStep++
|
||||||
|
|||||||
+38
-7
@@ -45,8 +45,7 @@ func (pq *priorityQueue) Pop() interface{} {
|
|||||||
return item
|
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))
|
canvas := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||||
draw.Draw(canvas, canvas.Bounds(), image.NewUniform(color.White), image.Point{}, draw.Src)
|
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
|
return canvas, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var allLakePixels []image.Point
|
var allLakes [][]image.Point
|
||||||
randSrc := rand.New(rand.NewSource(seed))
|
randSrc := rand.New(rand.NewSource(seed))
|
||||||
|
|
||||||
// 1. Divide the image into a grid
|
// 1. Divide the image into a grid
|
||||||
@@ -86,6 +85,8 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentLake []image.Point
|
||||||
|
|
||||||
// Each lake gets a random size within the defined range
|
// Each lake gets a random size within the defined range
|
||||||
lakeSize := lakeSizeLower
|
lakeSize := lakeSizeLower
|
||||||
if lakeSizeUpper > lakeSizeLower {
|
if lakeSizeUpper > lakeSizeLower {
|
||||||
@@ -147,7 +148,7 @@ func GenerateLakes(width, height, numLakes int, lakeSizeLower, lakeSizeUpper flo
|
|||||||
|
|
||||||
// The pixel is valid, claim it.
|
// The pixel is valid, claim it.
|
||||||
canvas.Set(current.point.X, current.point.Y, color.RGBA{R: 0, G: 0, B: 255, A: 255})
|
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++
|
lakeCount++
|
||||||
|
|
||||||
// Add neighbors, constrained to the chunk rectangle
|
// 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 {
|
type River struct {
|
||||||
@@ -181,7 +185,7 @@ type River struct {
|
|||||||
Points []image.Point
|
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 {
|
if numRivers == 0 {
|
||||||
return inputImage, nil
|
return inputImage, nil
|
||||||
}
|
}
|
||||||
@@ -197,8 +201,12 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
|
|||||||
avgDim := float64(width+height) / 2.0
|
avgDim := float64(width+height) / 2.0
|
||||||
|
|
||||||
isWater := make(map[image.Point]bool)
|
isWater := make(map[image.Point]bool)
|
||||||
for _, p := range lakePixels {
|
lakePixelMap := make(map[image.Point]int)
|
||||||
|
for i, lake := range lakes {
|
||||||
|
for _, p := range lake {
|
||||||
isWater[p] = true
|
isWater[p] = true
|
||||||
|
lakePixelMap[p] = i
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rivers := make([]River, numRivers)
|
rivers := make([]River, numRivers)
|
||||||
@@ -232,7 +240,14 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
|
|||||||
|
|
||||||
for _, p := range path {
|
for _, p := range path {
|
||||||
if isWater[p] {
|
if isWater[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
|
r.End = p
|
||||||
|
}
|
||||||
path = calculatePath(r.Start, r.End, curvyness/100.0, avgDim, randSrc, numControlPoints)
|
path = calculatePath(r.Start, r.End, curvyness/100.0, avgDim, randSrc, numControlPoints)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -242,6 +257,7 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
|
|||||||
radius := riverWidthPx / 2.0
|
radius := riverWidthPx / 2.0
|
||||||
|
|
||||||
for _, p := range path {
|
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)
|
drawCircle(canvas, p, radius, color.RGBA{R: 0, G: 0, B: 255, A: 255}, &allRiverPixels, isWater)
|
||||||
}
|
}
|
||||||
r.Points = path
|
r.Points = path
|
||||||
@@ -250,6 +266,21 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
|
|||||||
return canvas, allRiverPixels
|
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 {
|
func getPointOnEdge(width, height, edge int, randSrc *rand.Rand) image.Point {
|
||||||
switch edge {
|
switch edge {
|
||||||
case 0: // Top
|
case 0: // Top
|
||||||
|
|||||||
Reference in New Issue
Block a user