added bump map

This commit is contained in:
Grimsace
2026-02-09 10:13:36 -06:00
parent 49751d51d3
commit 391c3c473b
2 changed files with 103 additions and 2 deletions
+57
View File
@@ -0,0 +1,57 @@
package main
import (
"image"
"image/color"
"math"
)
// GenerateBumpMap creates a bump map from a heightmap.
func GenerateBumpMap(heightmap *image.RGBA, width, height int, depth float64) *image.RGBA {
bumpMap := image.NewRGBA(image.Rect(0, 0, width, height))
sobelX := [][]int{
{-1, 0, 1},
{-2, 0, 2},
{-1, 0, 1},
}
sobelY := [][]int{
{-1, -2, -1},
{0, 0, 0},
{1, 2, 1},
}
for y := 1; y < height-1; y++ {
for x := 1; x < width-1; x++ {
var gx, gy float64
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
gray, _, _, _ := heightmap.At(x+i-1, y+j-1).RGBA()
intensity := float64(gray >> 8)
gx += intensity * float64(sobelX[j][i])
gy += intensity * float64(sobelY[j][i])
}
}
nx := gx
ny := gy
nz := 1.0 / depth
length := math.Sqrt(nx*nx + ny*ny + nz*nz)
if length > 0 {
nx /= length
ny /= length
nz /= length
}
r := uint8((nx + 1.0) * 127.5)
g := uint8((ny + 1.0) * 127.5)
b := uint8(nz * 255.0)
bumpMap.Set(x, y, color.RGBA{R: r, G: g, B: b, A: 255})
}
}
return bumpMap
}
+46 -2
View File
@@ -49,6 +49,9 @@ func main() {
heightmapImg := &canvas.Image{
FillMode: canvas.ImageFillContain,
}
bumpmapImg := &canvas.Image{
FillMode: canvas.ImageFillContain,
}
// Initialize slices to store generated map features
var lakes [][]image.Point
@@ -67,6 +70,7 @@ func main() {
appConfigDir := filepath.Join(configDir, "rpgcitymakerreborn")
canvasPath := filepath.Join(appConfigDir, "canvas.png")
heightmapPath := filepath.Join(appConfigDir, "heightmap.png")
bumpmapPath := filepath.Join(appConfigDir, "bumpmap.png")
// Save settings and images on window close
w.SetOnClosed(func() {
@@ -97,6 +101,18 @@ func main() {
}
}
}
if bumpmapImg.Image != nil {
bumpmapFile, err := os.Create(bumpmapPath)
if err != nil {
log.Println("Failed to create bumpmap file:", err)
} else {
defer bumpmapFile.Close()
if err := png.Encode(bumpmapFile, bumpmapImg.Image); err != nil {
log.Println("Failed to encode bumpmap image:", err)
}
}
}
})
// Load previously saved images
@@ -118,6 +134,15 @@ func main() {
}
}
bumpmapFile, err := os.Open(bumpmapPath)
if err == nil {
defer bumpmapFile.Close()
img, err := png.Decode(bumpmapFile)
if err == nil {
bumpmapImg.Image = img
}
}
// Generate initial images if none are loaded
if canvasImg.Image == nil || heightmapImg.Image == nil {
@@ -177,7 +202,11 @@ func main() {
// Step 10: Applying Roughness
compositeImg := ApplyRoughness(flattenedHeightmap, settings.Roughness)
// Step 11: Generating Bump Map
bumpMap := GenerateBumpMap(compositeImg.(*image.RGBA), settings.Width, settings.Height, 0.10)
heightmapImg.Image = compositeImg
bumpmapImg.Image = bumpMap
canvasImg.Image = finalImage
@@ -388,6 +417,9 @@ func main() {
exportHeightmapBtn := widget.NewButton("Export Heightmap", func() {
showSaveDialog(w, heightmapImg.Image, settings)
})
exportBumpmapBtn := widget.NewButton("Export Bump Map", func() {
showSaveDialog(w, bumpmapImg.Image, settings)
})
exportMasksBtn := widget.NewButton("Export Masks", func() {
showMasksSaveDialog(w, canvasImg.Image, heightmapImg.Image, settings, lakes, riverPixels, treePixels, roadPixels, bridgePixels, buildingPixels, buildings)
})
@@ -502,13 +534,23 @@ func main() {
})
treePixels = GenerateTrees(finalImage, allWaterPixels, roadPixels, buildingPixels, settings.MinTreeSize, settings.MaxTreeSize, settings.TreeCoverage, settings.TreeClumpiness, seedProvider.Next())
// Step 10: Finalizing Images
// Step 10: Generating Bump Map
currentStep++
fyne.Do(func() {
progressBar.SetText(fmt.Sprintf("Step %d/%d: Generating Bump Map", currentStep, steps))
progressBar.SetValue(float64(currentStep) / float64(steps))
})
bumpMap := GenerateBumpMap(compositeImg.(*image.RGBA), settings.Width, settings.Height, 0.10)
// Step 11: Finalizing Images
currentStep++
fyne.Do(func() {
progressBar.SetText(fmt.Sprintf("Step %d/%d: Finalizing Images", currentStep, steps))
progressBar.SetValue(float64(currentStep) / float64(steps))
heightmapImg.Image = compositeImg
heightmapImg.Refresh()
bumpmapImg.Image = bumpMap
bumpmapImg.Refresh()
canvasImg.Image = finalImage
canvasImg.Refresh()
@@ -884,6 +926,7 @@ func main() {
widget.NewSeparator(),
exportCanvasBtn,
exportHeightmapBtn,
exportBumpmapBtn,
exportMasksBtn,
))
// Create the main layout using a horizontal split
@@ -900,9 +943,10 @@ func main() {
tabs,
)
right := container.NewGridWithRows(2,
right := container.NewGridWithRows(3,
canvasImg,
heightmapImg,
bumpmapImg,
)
split := container.NewHSplit(