export masks added
This commit is contained in:
@@ -1,19 +1,21 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"archive/tar"
|
||||||
|
"archive/zip"
|
||||||
|
"bytes"
|
||||||
|
"compress/gzip"
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
"image/color"
|
"image/color"
|
||||||
"log"
|
"image/jpeg"
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"image/png"
|
"image/png"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"image/jpeg"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
"fyne.io/fyne/v2"
|
"fyne.io/fyne/v2"
|
||||||
"fyne.io/fyne/v2/app"
|
"fyne.io/fyne/v2/app"
|
||||||
@@ -46,15 +48,17 @@ func main() {
|
|||||||
FillMode: canvas.ImageFillContain,
|
FillMode: canvas.ImageFillContain,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var lakes [][]image.Point
|
||||||
|
var riverPixels []image.Point
|
||||||
|
var treePixels []image.Point
|
||||||
|
|
||||||
configDir, err := os.UserConfigDir()
|
configDir, err := os.UserConfigDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Failed to get user config dir:", err)
|
log.Fatal("Failed to get user config dir:", err)
|
||||||
}
|
}
|
||||||
appConfigDir := filepath.Join(configDir, "rpgcitymakerreborn")
|
appConfigDir := filepath.Join(configDir, "rpgcitymakerreborn")
|
||||||
|
|
||||||
canvasPath := filepath.Join(appConfigDir, "canvas.png")
|
canvasPath := filepath.Join(appConfigDir, "canvas.png")
|
||||||
heightmapPath := filepath.Join(appConfigDir, "heightmap.png")
|
heightmapPath := filepath.Join(appConfigDir, "heightmap.png")
|
||||||
|
|
||||||
w.SetOnClosed(func() {
|
w.SetOnClosed(func() {
|
||||||
if err := settings.Save(); err != nil {
|
if err := settings.Save(); err != nil {
|
||||||
log.Println("Error saving settings:", err)
|
log.Println("Error saving settings:", err)
|
||||||
@@ -84,7 +88,6 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
canvasFile, err := os.Open(canvasPath)
|
canvasFile, err := os.Open(canvasPath)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
defer canvasFile.Close()
|
defer canvasFile.Close()
|
||||||
@@ -106,8 +109,10 @@ 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, lakes := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
|
var lakeImage image.Image
|
||||||
riverImage, riverPixels := GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, settings.Seed, noiseImg)
|
lakeImage, lakes = GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
|
||||||
|
var riverImage image.Image
|
||||||
|
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, settings.Seed, noiseImg)
|
||||||
finalImage := riverImage.(*image.RGBA)
|
finalImage := riverImage.(*image.RGBA)
|
||||||
|
|
||||||
var flatLakePixels []image.Point
|
var flatLakePixels []image.Point
|
||||||
@@ -116,7 +121,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
allWaterPixels := append(flatLakePixels, riverPixels...)
|
allWaterPixels := append(flatLakePixels, riverPixels...)
|
||||||
|
|
||||||
GenerateTrees(finalImage, allWaterPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, settings.Seed)
|
treePixels = 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)
|
||||||
heightmapImg.Image = compositeImg
|
heightmapImg.Image = compositeImg
|
||||||
@@ -266,6 +271,9 @@ func main() {
|
|||||||
exportHeightmapBtn := widget.NewButton("Export Heightmap", func() {
|
exportHeightmapBtn := widget.NewButton("Export Heightmap", func() {
|
||||||
showSaveDialog(w, heightmapImg.Image, settings)
|
showSaveDialog(w, heightmapImg.Image, settings)
|
||||||
})
|
})
|
||||||
|
exportMasksBtn := widget.NewButton("Export Masks", func() {
|
||||||
|
showMasksSaveDialog(w, canvasImg.Image, heightmapImg.Image, settings, lakes, riverPixels, treePixels)
|
||||||
|
})
|
||||||
|
|
||||||
generateBtn = widget.NewButton("Generate", func() {
|
generateBtn = widget.NewButton("Generate", func() {
|
||||||
go func() {
|
go func() {
|
||||||
@@ -295,7 +303,8 @@ func main() {
|
|||||||
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, lakes := GenerateLakes(settings.Width, settings.Height, settings.Lakes, settings.LakeSizeLower, settings.LakeSizeUpper, noiseImg, settings.Seed)
|
var lakeImage image.Image
|
||||||
|
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++
|
||||||
@@ -303,7 +312,8 @@ func main() {
|
|||||||
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, lakes, settings.Seed, noiseImg)
|
var riverImage image.Image
|
||||||
|
riverImage, riverPixels = GenerateRivers(settings.Width, settings.Height, settings.Rivers, settings.MinRiverWidth, settings.MaxRiverWidth, settings.RiverCurvyness, lakeImage, lakes, settings.Seed, noiseImg)
|
||||||
|
|
||||||
finalImage := riverImage.(*image.RGBA)
|
finalImage := riverImage.(*image.RGBA)
|
||||||
var flatLakePixels []image.Point
|
var flatLakePixels []image.Point
|
||||||
@@ -334,7 +344,7 @@ func main() {
|
|||||||
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Trees", currentStep, steps))
|
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Trees", currentStep, steps))
|
||||||
progressBar.SetValue(float64(currentStep) / float64(steps))
|
progressBar.SetValue(float64(currentStep) / float64(steps))
|
||||||
})
|
})
|
||||||
GenerateTrees(finalImage, allWaterPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, settings.Seed)
|
treePixels = GenerateTrees(finalImage, allWaterPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, settings.Seed)
|
||||||
|
|
||||||
// Step 7: Finalizing Images
|
// Step 7: Finalizing Images
|
||||||
currentStep++
|
currentStep++
|
||||||
@@ -452,6 +462,7 @@ func main() {
|
|||||||
widget.NewSeparator(),
|
widget.NewSeparator(),
|
||||||
exportCanvasBtn,
|
exportCanvasBtn,
|
||||||
exportHeightmapBtn,
|
exportHeightmapBtn,
|
||||||
|
exportMasksBtn,
|
||||||
))
|
))
|
||||||
|
|
||||||
tabs := container.NewAppTabs(
|
tabs := container.NewAppTabs(
|
||||||
@@ -479,6 +490,209 @@ func main() {
|
|||||||
w.SetContent(split)
|
w.SetContent(split)
|
||||||
w.ShowAndRun()
|
w.ShowAndRun()
|
||||||
}
|
}
|
||||||
|
func getImageData(img image.Image, format string) (*bytes.Buffer, error) {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
var err error
|
||||||
|
switch format {
|
||||||
|
case "PNG":
|
||||||
|
err = png.Encode(buf, img)
|
||||||
|
case "JPG":
|
||||||
|
err = jpeg.Encode(buf, img, nil)
|
||||||
|
case "WEBP":
|
||||||
|
err = webp.Encode(buf, img, &webp.Options{Lossless: true})
|
||||||
|
}
|
||||||
|
return buf, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func showMasksSaveDialog(win fyne.Window, canvasImg, heightmapImg image.Image, settings *Settings, lakes [][]image.Point, riverPixels, treePixels []image.Point) {
|
||||||
|
fileNameEntry := widget.NewEntry()
|
||||||
|
fileNameEntry.SetPlaceHolder("masks_folder")
|
||||||
|
|
||||||
|
formatSelect := widget.NewSelect([]string{"PNG", "JPG", "WEBP"}, nil)
|
||||||
|
formatSelect.SetSelected("PNG")
|
||||||
|
|
||||||
|
packageSelect := widget.NewSelect([]string{"Folder", "tar.gz", "zip"}, nil)
|
||||||
|
packageSelect.SetSelected("Folder")
|
||||||
|
|
||||||
|
pathLabel := widget.NewLabel(settings.LastExportPath)
|
||||||
|
|
||||||
|
browseBtn := widget.NewButton("Browse", func() {
|
||||||
|
dialog.ShowFolderOpen(func(uri fyne.ListableURI, err error) {
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error opening folder dialog:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if uri == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
settings.LastExportPath = uri.Path()
|
||||||
|
pathLabel.SetText(settings.LastExportPath)
|
||||||
|
}, win)
|
||||||
|
})
|
||||||
|
|
||||||
|
content := container.NewVBox(
|
||||||
|
widget.NewLabel("Save to:"),
|
||||||
|
container.NewBorder(nil, nil, nil, browseBtn, pathLabel),
|
||||||
|
widget.NewLabel("Folder Name:"),
|
||||||
|
fileNameEntry,
|
||||||
|
widget.NewLabel("Format:"),
|
||||||
|
formatSelect,
|
||||||
|
widget.NewLabel("Packaging:"),
|
||||||
|
packageSelect,
|
||||||
|
)
|
||||||
|
|
||||||
|
saveDialog := dialog.NewCustom("Export Masks", "Cancel", content, win)
|
||||||
|
|
||||||
|
saveBtn := widget.NewButton("Save", func() {
|
||||||
|
folderName := fileNameEntry.Text
|
||||||
|
if folderName == "" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
imgFormat := strings.ToLower(formatSelect.Selected)
|
||||||
|
bounds := canvasImg.Bounds()
|
||||||
|
|
||||||
|
// Create mask images
|
||||||
|
lakeMask := image.NewGray(bounds)
|
||||||
|
for _, lake := range lakes {
|
||||||
|
for _, p := range lake {
|
||||||
|
lakeMask.SetGray(p.X, p.Y, color.Gray{Y: 255})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
riverMask := image.NewGray(bounds)
|
||||||
|
for _, p := range riverPixels {
|
||||||
|
riverMask.SetGray(p.X, p.Y, color.Gray{Y: 255})
|
||||||
|
}
|
||||||
|
treeMask := image.NewGray(bounds)
|
||||||
|
for _, p := range treePixels {
|
||||||
|
treeMask.SetGray(p.X, p.Y, color.Gray{Y: 255})
|
||||||
|
}
|
||||||
|
|
||||||
|
imagesToSave := map[string]image.Image{
|
||||||
|
"canvas." + imgFormat: canvasImg,
|
||||||
|
"heightmap." + imgFormat: heightmapImg,
|
||||||
|
"lakes_mask." + imgFormat: lakeMask,
|
||||||
|
"rivers_mask." + imgFormat: riverMask,
|
||||||
|
"trees_mask." + imgFormat: treeMask,
|
||||||
|
}
|
||||||
|
|
||||||
|
switch packageSelect.Selected {
|
||||||
|
case "Folder":
|
||||||
|
exportPath := filepath.Join(pathLabel.Text, folderName)
|
||||||
|
if err := os.MkdirAll(exportPath, 0755); err != nil {
|
||||||
|
log.Println("Error creating directory:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
settings.LastExportPath = exportPath
|
||||||
|
for name, img := range imagesToSave {
|
||||||
|
saveImage(img, filepath.Join(exportPath, name))
|
||||||
|
}
|
||||||
|
case "tar.gz":
|
||||||
|
filePath := filepath.Join(pathLabel.Text, folderName+".tar.gz")
|
||||||
|
settings.LastExportPath = filepath.Dir(filePath)
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error creating archive:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
gw := gzip.NewWriter(file)
|
||||||
|
defer gw.Close()
|
||||||
|
tw := tar.NewWriter(gw)
|
||||||
|
defer tw.Close()
|
||||||
|
|
||||||
|
for name, img := range imagesToSave {
|
||||||
|
buf, err := getImageData(img, formatSelect.Selected)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error encoding image %s: %v\n", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
hdr := &tar.Header{
|
||||||
|
Name: name,
|
||||||
|
Mode: 0644,
|
||||||
|
Size: int64(buf.Len()),
|
||||||
|
}
|
||||||
|
if err := tw.WriteHeader(hdr); err != nil {
|
||||||
|
log.Printf("Error writing tar header for %s: %v\n", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := tw.Write(buf.Bytes()); err != nil {
|
||||||
|
log.Printf("Error writing tar data for %s: %v\n", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "zip":
|
||||||
|
filePath := filepath.Join(pathLabel.Text, folderName+".zip")
|
||||||
|
settings.LastExportPath = filepath.Dir(filePath)
|
||||||
|
file, err := os.Create(filePath)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error creating archive:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
zw := zip.NewWriter(file)
|
||||||
|
defer zw.Close()
|
||||||
|
|
||||||
|
for name, img := range imagesToSave {
|
||||||
|
buf, err := getImageData(img, formatSelect.Selected)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error encoding image %s: %v\n", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
f, err := zw.Create(name)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("Error creating zip entry for %s: %v\n", name, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if _, err := f.Write(buf.Bytes()); err != nil {
|
||||||
|
log.Printf("Error writing zip data for %s: %v\n", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDialog.Hide()
|
||||||
|
})
|
||||||
|
saveBtn.Disable()
|
||||||
|
|
||||||
|
fileNameEntry.OnChanged = func(text string) {
|
||||||
|
if text == "" {
|
||||||
|
saveBtn.Disable()
|
||||||
|
} else {
|
||||||
|
saveBtn.Enable()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
saveDialog.SetButtons([]fyne.CanvasObject{
|
||||||
|
widget.NewButton("Cancel", func() {
|
||||||
|
saveDialog.Hide()
|
||||||
|
}),
|
||||||
|
saveBtn,
|
||||||
|
})
|
||||||
|
|
||||||
|
saveDialog.Show()
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveImage(img image.Image, path string) {
|
||||||
|
file, err := os.Create(path)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Error creating file:", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
ext := strings.ToLower(filepath.Ext(path))
|
||||||
|
switch ext {
|
||||||
|
case ".png":
|
||||||
|
err = png.Encode(file, img)
|
||||||
|
case ".jpg":
|
||||||
|
err = jpeg.Encode(file, img, nil)
|
||||||
|
case ".webp":
|
||||||
|
err = webp.Encode(file, img, &webp.Options{Lossless: true})
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
log.Println("Failed to encode image:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func showSaveDialog(win fyne.Window, img image.Image, settings *Settings) {
|
func showSaveDialog(win fyne.Window, img image.Image, settings *Settings) {
|
||||||
fileNameEntry := widget.NewEntry()
|
fileNameEntry := widget.NewEntry()
|
||||||
@@ -522,25 +736,7 @@ func showSaveDialog(win fyne.Window, img image.Image, settings *Settings) {
|
|||||||
|
|
||||||
filePath := filepath.Join(pathLabel.Text, fileName+"."+strings.ToLower(formatSelect.Selected))
|
filePath := filepath.Join(pathLabel.Text, fileName+"."+strings.ToLower(formatSelect.Selected))
|
||||||
settings.LastExportPath = filepath.Dir(filePath)
|
settings.LastExportPath = filepath.Dir(filePath)
|
||||||
|
saveImage(img, filePath)
|
||||||
file, err := os.Create(filePath)
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Error creating file:", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer file.Close()
|
|
||||||
|
|
||||||
switch formatSelect.Selected {
|
|
||||||
case "PNG":
|
|
||||||
err = png.Encode(file, img)
|
|
||||||
case "JPG":
|
|
||||||
err = jpeg.Encode(file, img, nil)
|
|
||||||
case "WEBP":
|
|
||||||
err = webp.Encode(file, img, &webp.Options{Lossless: true})
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Failed to encode image:", err)
|
|
||||||
}
|
|
||||||
saveDialog.Hide()
|
saveDialog.Hide()
|
||||||
})
|
})
|
||||||
saveBtn.Disable()
|
saveBtn.Disable()
|
||||||
|
|||||||
+7
-4
@@ -85,25 +85,25 @@ func DarkenLakeAreas(heightmap image.Image, lakePixels []image.Point) image.Imag
|
|||||||
return composite
|
return composite
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateTrees(img *image.RGBA, lakePixels []image.Point, minTreeSize, maxTreeSize, treeCoverage, treeClumpiness float64, seed int64) {
|
func GenerateTrees(img *image.RGBA, lakePixels []image.Point, minTreeSize, maxTreeSize, treeCoverage, treeClumpiness float64, seed int64) []image.Point {
|
||||||
width := img.Bounds().Dx()
|
width := img.Bounds().Dx()
|
||||||
height := img.Bounds().Dy()
|
height := img.Bounds().Dy()
|
||||||
|
|
||||||
// 1. Calculate number of trees to place from coverage %.
|
// 1. Calculate number of trees to place from coverage %.
|
||||||
avgTreeSize := (minTreeSize + maxTreeSize) / 2
|
avgTreeSize := (minTreeSize + maxTreeSize) / 2
|
||||||
if avgTreeSize <= 0 {
|
if avgTreeSize <= 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
avgRadius := avgTreeSize / 2
|
avgRadius := avgTreeSize / 2
|
||||||
avgTreeArea := math.Pi * avgRadius * avgRadius
|
avgTreeArea := math.Pi * avgRadius * avgRadius
|
||||||
if avgTreeArea == 0 {
|
if avgTreeArea == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
totalArea := float64(width * height)
|
totalArea := float64(width * height)
|
||||||
targetTreePixels := totalArea * (treeCoverage / 100.0)
|
targetTreePixels := totalArea * (treeCoverage / 100.0)
|
||||||
numTreesToPlace := int(targetTreePixels / avgTreeArea)
|
numTreesToPlace := int(targetTreePixels / avgTreeArea)
|
||||||
if numTreesToPlace == 0 {
|
if numTreesToPlace == 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Generate a simplex noise map for tree placement.
|
// 2. Generate a simplex noise map for tree placement.
|
||||||
@@ -146,6 +146,7 @@ func GenerateTrees(img *image.RGBA, lakePixels []image.Point, minTreeSize, maxTr
|
|||||||
return treeNoiseMap.GrayAt(p.X, p.Y).Y >= threshold && !isLake[p]
|
return treeNoiseMap.GrayAt(p.X, p.Y).Y >= threshold && !isLake[p]
|
||||||
}, seed)
|
}, seed)
|
||||||
|
|
||||||
|
var treePixels []image.Point
|
||||||
// 5. Draw the trees.
|
// 5. Draw the trees.
|
||||||
for _, p := range allPoints {
|
for _, p := range allPoints {
|
||||||
size := minTreeSize + randSrc.Float64()*(maxTreeSize-minTreeSize)
|
size := minTreeSize + randSrc.Float64()*(maxTreeSize-minTreeSize)
|
||||||
@@ -165,10 +166,12 @@ func GenerateTrees(img *image.RGBA, lakePixels []image.Point, minTreeSize, maxTr
|
|||||||
// Blend the tree color with the background
|
// Blend the tree color with the background
|
||||||
// For simplicity, we just set a solid color for now.
|
// For simplicity, we just set a solid color for now.
|
||||||
img.Set(x, y, color.RGBA{R: 0, G: 100, B: 0, A: 255})
|
img.Set(x, y, color.RGBA{R: 0, G: 100, B: 0, A: 255})
|
||||||
|
treePixels = append(treePixels, pt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return treePixels
|
||||||
}
|
}
|
||||||
|
|
||||||
func poissonDiscSampling(width, height int, minRadius float64, k int, initialPoints []image.Point, isValid func(image.Point) bool, seed int64) []image.Point {
|
func poissonDiscSampling(width, height int, minRadius float64, k int, initialPoints []image.Point, isValid func(image.Point) bool, seed int64) []image.Point {
|
||||||
|
|||||||
Reference in New Issue
Block a user