added user settings to control river width variability and bank detail
This commit is contained in:
@@ -158,7 +158,7 @@ func main() {
|
||||
// Step 3: Generating Rivers
|
||||
var riverImage image.Image
|
||||
|
||||
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg)
|
||||
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg, settings.RiverWidthVariability, settings.RiverEdgeRoughness)
|
||||
|
||||
finalImage := riverImage.(*image.RGBA)
|
||||
|
||||
@@ -338,6 +338,31 @@ func main() {
|
||||
val, _ := riverCurvynessSlider.value.Get()
|
||||
settings.RiverCurvyness = val
|
||||
}))
|
||||
|
||||
riverWidthVariabilitySlider := newNumericInputSlider(0, 100, settings.RiverWidthVariability, "%.0f%%", "River Width Variability")
|
||||
riverWidthVariabilitySlider.entry.OnChanged = func(s string) {
|
||||
riverWidthVariabilitySlider.validate(s, func(hasError bool) {
|
||||
errorStates["riverWidthVariability"] = hasError
|
||||
updateGenerateBtnState()
|
||||
})
|
||||
}
|
||||
riverWidthVariabilitySlider.value.AddListener(binding.NewDataListener(func() {
|
||||
val, _ := riverWidthVariabilitySlider.value.Get()
|
||||
settings.RiverWidthVariability = val
|
||||
}))
|
||||
|
||||
riverEdgeRoughnessSlider := newNumericInputSlider(0, 100, settings.RiverEdgeRoughness, "%.0f%%", "River Edge Roughness")
|
||||
riverEdgeRoughnessSlider.entry.OnChanged = func(s string) {
|
||||
riverEdgeRoughnessSlider.validate(s, func(hasError bool) {
|
||||
errorStates["riverEdgeRoughness"] = hasError
|
||||
updateGenerateBtnState()
|
||||
})
|
||||
}
|
||||
riverEdgeRoughnessSlider.value.AddListener(binding.NewDataListener(func() {
|
||||
val, _ := riverEdgeRoughnessSlider.value.Get()
|
||||
settings.RiverEdgeRoughness = val
|
||||
}))
|
||||
|
||||
minTreeSizeSlider := newNumericInputSlider(1, 150, settings.MinTreeSize, "%.0fpx", "Min Tree Size")
|
||||
minTreeSizeSlider.entry.OnChanged = func(s string) {
|
||||
minTreeSizeSlider.validate(s, func(hasError bool) {
|
||||
@@ -516,7 +541,7 @@ func main() {
|
||||
progressBar.SetValue(3.0 / 11.0)
|
||||
})
|
||||
var riverImage image.Image
|
||||
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg)
|
||||
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, seedProvider.Next(), noiseImg, settings.RiverWidthVariability, settings.RiverEdgeRoughness)
|
||||
|
||||
finalImage := riverImage.(*image.RGBA)
|
||||
|
||||
@@ -682,6 +707,8 @@ func main() {
|
||||
minRiverWidthSlider,
|
||||
maxRiverWidthSlider,
|
||||
riverCurvynessSlider,
|
||||
riverWidthVariabilitySlider,
|
||||
riverEdgeRoughnessSlider,
|
||||
))
|
||||
|
||||
roadsTab := container.NewTabItem("Roads", container.NewVBox(
|
||||
|
||||
+38
-34
@@ -16,13 +16,15 @@ type Settings struct {
|
||||
Height int `json:"height"`
|
||||
|
||||
// Water settings
|
||||
Lakes int `json:"lakes"`
|
||||
LakeSizeLower float64 `json:"lake_size_lower"`
|
||||
LakeSizeUpper float64 `json:"lake_size_upper"`
|
||||
Rivers int `json:"rivers"`
|
||||
MinRiverWidth float64 `json:"min_river_width"`
|
||||
MaxRiverWidth float64 `json:"max_river_width"`
|
||||
RiverCurvyness float64 `json:"river_curvyness"`
|
||||
Lakes int `json:"lakes"`
|
||||
LakeSizeLower float64 `json:"lake_size_lower"`
|
||||
LakeSizeUpper float64 `json:"lake_size_upper"`
|
||||
Rivers int `json:"rivers"`
|
||||
MinRiverWidth float64 `json:"min_river_width"`
|
||||
MaxRiverWidth float64 `json:"max_river_width"`
|
||||
RiverCurvyness float64 `json:"river_curvyness"`
|
||||
RiverWidthVariability float64 `json:"river_width_variability"`
|
||||
RiverEdgeRoughness float64 `json:"river_edge_roughness"`
|
||||
|
||||
// Tree settings
|
||||
MinTreeSize float64 `json:"min_tree_size"`
|
||||
@@ -106,33 +108,35 @@ func LoadSettings() (*Settings, error) {
|
||||
homeDir = "."
|
||||
}
|
||||
return &Settings{
|
||||
Detail: 1,
|
||||
Roughness: 0,
|
||||
Width: 300,
|
||||
Height: 300,
|
||||
Lakes: 0,
|
||||
LakeSizeLower: 1,
|
||||
LakeSizeUpper: 5,
|
||||
MinTreeSize: 5,
|
||||
MaxTreeSize: 20,
|
||||
TreeCoverage: 20,
|
||||
TreeClumpiness: 50,
|
||||
Seed: time.Now().UnixNano(),
|
||||
Rivers: 0,
|
||||
MinRiverWidth: 1,
|
||||
MaxRiverWidth: 5,
|
||||
RiverCurvyness: 50,
|
||||
NumRoads: 100,
|
||||
MinRoadWidth: 2,
|
||||
MaxRoadWidth: 8,
|
||||
RoadExits: 5,
|
||||
RoadCurvyness: 50,
|
||||
RoadDistribution: 50,
|
||||
NumBuildings: 200,
|
||||
MinBuildingSize: 10,
|
||||
MaxBuildingSize: 30,
|
||||
BuildingDistribution: 20,
|
||||
BuildingShape: "mixed",
|
||||
Detail: 1,
|
||||
Roughness: 0,
|
||||
Width: 300,
|
||||
Height: 300,
|
||||
Lakes: 0,
|
||||
LakeSizeLower: 1,
|
||||
LakeSizeUpper: 5,
|
||||
MinTreeSize: 5,
|
||||
MaxTreeSize: 20,
|
||||
TreeCoverage: 20,
|
||||
TreeClumpiness: 50,
|
||||
Seed: time.Now().UnixNano(),
|
||||
Rivers: 0,
|
||||
MinRiverWidth: 1,
|
||||
MaxRiverWidth: 5,
|
||||
RiverCurvyness: 50,
|
||||
RiverWidthVariability: 50,
|
||||
RiverEdgeRoughness: 50,
|
||||
NumRoads: 100,
|
||||
MinRoadWidth: 2,
|
||||
MaxRoadWidth: 8,
|
||||
RoadExits: 5,
|
||||
RoadCurvyness: 50,
|
||||
RoadDistribution: 50,
|
||||
NumBuildings: 200,
|
||||
MinBuildingSize: 10,
|
||||
MaxBuildingSize: 30,
|
||||
BuildingDistribution: 20,
|
||||
BuildingShape: "mixed",
|
||||
BuildingShapeRatios: map[string]float64{
|
||||
"squares": 40,
|
||||
"circles": 30,
|
||||
|
||||
@@ -190,7 +190,7 @@ type River struct {
|
||||
}
|
||||
|
||||
// GenerateRivers creates rivers on the map.
|
||||
func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness float64, inputImage image.Image, lakes [][]image.Point, seed int64, heightmap image.Image) (image.Image, []image.Point) {
|
||||
func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness float64, inputImage image.Image, lakes [][]image.Point, seed int64, heightmap image.Image, riverWidthVariability, riverEdgeRoughness float64) (image.Image, []image.Point) {
|
||||
if numRivers == 0 {
|
||||
return inputImage, nil
|
||||
}
|
||||
@@ -267,7 +267,7 @@ func GenerateRivers(width, height, numRivers int, minWidth, maxWidth, curvyness
|
||||
radius := riverWidthPx / 2.0
|
||||
|
||||
for _, p := range path {
|
||||
drawCircle(canvas, p, radius, color.RGBA{R: 0, G: 0, B: 255, A: 255}, &allRiverPixels, isWater, heightmap)
|
||||
drawCircle(canvas, p, radius, color.RGBA{R: 0, G: 0, B: 255, A: 255}, &allRiverPixels, isWater, heightmap, riverWidthVariability, riverEdgeRoughness)
|
||||
}
|
||||
r.Points = path
|
||||
}
|
||||
@@ -410,14 +410,19 @@ func getPointOnEdge(width, height, edge int, randSrc *rand.Rand) image.Point {
|
||||
|
||||
// drawCircle draws a circle on the image and adds its pixels to the given slice.
|
||||
// The outer edges are roughened using dual sin waves for natural-looking banks.
|
||||
func drawCircle(img *image.RGBA, center image.Point, radius float64, c color.Color, pixels *[]image.Point, isWater map[image.Point]bool, heightmap image.Image) {
|
||||
// riverWidthVariability controls the amplitude of width changes (0-100%).
|
||||
// riverEdgeRoughness controls the detail level of the edge roughness (0-100%).
|
||||
func drawCircle(img *image.RGBA, center image.Point, radius float64, c color.Color, pixels *[]image.Point, isWater map[image.Point]bool, heightmap image.Image, riverWidthVariability, riverEdgeRoughness float64) {
|
||||
bounds := img.Bounds()
|
||||
|
||||
// Calculate dual sin wave amplitudes for outer edge roughening
|
||||
// Large amplitude represents major variations in river width
|
||||
// Small amplitude is 1/4 of large for subtle details
|
||||
largeAmplitude := radius * 0.25
|
||||
smallAmplitude := largeAmplitude / 4.0
|
||||
// Large amplitude represents major variations in river width (controlled by riverWidthVariability)
|
||||
// At 0%, no width variation; at 100%, amplitude is 50% of radius
|
||||
largeAmplitude := (radius * 0.5) * (riverWidthVariability / 100.0)
|
||||
|
||||
// Small amplitude is controlled by riverEdgeRoughness
|
||||
// At 0%, no detail; at 100%, detail amplitude equals large amplitude
|
||||
smallAmplitude := largeAmplitude * (riverEdgeRoughness / 100.0)
|
||||
|
||||
for y := int(math.Floor(float64(center.Y) - radius)); y <= int(math.Ceil(float64(center.Y)+radius)); y++ {
|
||||
for x := int(math.Floor(float64(center.X) - radius)); x <= int(math.Ceil(float64(center.X)+radius)); x++ {
|
||||
|
||||
Reference in New Issue
Block a user