changed how masks are stored for massive performance improvment and way less ram usage

This commit is contained in:
Grimsace
2026-02-26 13:03:48 -06:00
parent 1dd9bf2c13
commit d01cb7a247
6 changed files with 277 additions and 210 deletions
+33 -31
View File
@@ -62,7 +62,17 @@ func getBuildingSizeRangePixels(settings *Settings, width, height int) (float64,
}
// GenerateBuildings creates and places buildings on the map.
func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, roadPixels, allWaterPixels []image.Point, seed int64) ([][]image.Point, []image.Point) {
func GenerateBuildings(
img *image.RGBA,
width,
height int,
settings *Settings,
roadAnchors []image.Point,
waterMask,
roadMask,
exitRoadMask *PixelMask,
seed int64,
) ([][]image.Point, *PixelMask) {
// Early exit if no buildings are to be generated
if settings.NumBuildings == 0 {
return nil, nil
@@ -70,32 +80,25 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
randSrc := rand.New(rand.NewSource(seed))
buildingColor := color.RGBA{R: 128, G: 128, B: 128, A: 255} // Gray color for buildings
isWater := make(map[image.Point]bool)
for _, p := range allWaterPixels {
isWater[p] = true
if waterMask == nil {
waterMask = NewPixelMask(width, height)
}
isRoad := make(map[image.Point]bool)
for _, p := range roadPixels {
isRoad[p] = true
if roadMask == nil {
roadMask = NewPixelMask(width, height)
}
isExitRoad := make(map[image.Point]bool)
for _, p := range getExitRoadPixels() {
isExitRoad[p] = true
if exitRoadMask == nil {
exitRoadMask = NewPixelMask(width, height)
}
isBuilding := make(map[image.Point]bool)
buildingMask := NewPixelMask(width, height)
var buildings [][]image.Point
var allBuildingPixels []image.Point
var anchorPoints []image.Point
var normalRoadAnchors []image.Point
var exitRoadAnchors []image.Point
if len(roadPixels) > 0 {
anchorPoints = roadPixels
if len(roadAnchors) > 0 {
anchorPoints = roadAnchors
for _, p := range anchorPoints {
if isExitRoad[p] {
if exitRoadMask.GetPoint(p) {
exitRoadAnchors = append(exitRoadAnchors, p)
} else {
normalRoadAnchors = append(normalRoadAnchors, p)
@@ -106,7 +109,7 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
p := image.Point{X: x, Y: y}
if !isWater[p] {
if !waterMask.GetPoint(p) {
anchorPoints = append(anchorPoints, p)
}
}
@@ -129,7 +132,7 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
p := image.Point{X: x, Y: y}
if !isWater[p] && !isRoad[p] {
if !waterMask.GetPoint(p) && !roadMask.GetPoint(p) {
landPoints = append(landPoints, p)
}
}
@@ -196,17 +199,16 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
var ok bool
if shape == "procedural" {
pixels, ok = getProceduralBuildingPixels(center, size, settings, isWater, isRoad, isBuilding, width, height, randSrc)
pixels, ok = getProceduralBuildingPixels(center, size, settings, waterMask, roadMask, buildingMask, width, height, randSrc)
} else {
pixels, ok = getBuildingPixels(center, size, shape, isWater, isRoad, isBuilding, width, height, randSrc)
pixels, ok = getBuildingPixels(center, size, shape, waterMask, roadMask, buildingMask, width, height, randSrc)
}
if ok {
// If successful, draw the building and update data structures
for _, p := range pixels {
img.Set(p.X, p.Y, buildingColor)
isBuilding[p] = true
allBuildingPixels = append(allBuildingPixels, p)
buildingMask.SetPoint(p)
}
buildings = append(buildings, pixels)
buildingsPlaced++
@@ -214,11 +216,11 @@ func GenerateBuildings(img *image.RGBA, width, height int, settings *Settings, r
}
}
}
return buildings, allBuildingPixels
return buildings, buildingMask
}
// getProceduralBuildingPixels generates a complex building by connecting multiple shapes.
func getProceduralBuildingPixels(center image.Point, size float64, settings *Settings, isWater, isRoad, isBuilding map[image.Point]bool, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
func getProceduralBuildingPixels(center image.Point, size float64, settings *Settings, waterMask, roadMask, buildingMask *PixelMask, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
complexity := settings.MinBuildingComplexity
if settings.BuildingComplexityRatio > randSrc.Float64()*100 {
complexity = settings.MinBuildingComplexity + randSrc.Intn(settings.MaxBuildingComplexity-settings.MinBuildingComplexity+1)
@@ -293,7 +295,7 @@ func getProceduralBuildingPixels(center image.Point, size float64, settings *Set
continue
}
for _, p := range pixels {
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || waterMask.GetPoint(p) || roadMask.GetPoint(p) || buildingMask.GetPoint(p) {
return nil, false
}
if !pixelMap[p] {
@@ -436,7 +438,7 @@ func chooseShape(randSrc *rand.Rand, ratios map[string]float64) string {
}
// getBuildingPixels determines the pixels for a single building based on its shape and checks for collisions.
func getBuildingPixels(center image.Point, size float64, shape string, isWater, isRoad, isBuilding map[image.Point]bool, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
func getBuildingPixels(center image.Point, size float64, shape string, waterMask, roadMask, buildingMask *PixelMask, width, height int, randSrc *rand.Rand) ([]image.Point, bool) {
var pixels []image.Point
var halfSize = int(size / 2)
@@ -446,7 +448,7 @@ func getBuildingPixels(center image.Point, size float64, shape string, isWater,
for y := center.Y - halfSize; y <= center.Y+halfSize; y++ {
for x := center.X - halfSize; x <= center.X+halfSize; x++ {
p := image.Point{X: x, Y: y}
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || waterMask.GetPoint(p) || roadMask.GetPoint(p) || buildingMask.GetPoint(p) {
return nil, false // Collision detected
}
pixels = append(pixels, p)
@@ -459,7 +461,7 @@ func getBuildingPixels(center image.Point, size float64, shape string, isWater,
dx, dy := float64(x-center.X), float64(y-center.Y)
if dx*dx+dy*dy <= r2 {
p := image.Point{X: x, Y: y}
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || waterMask.GetPoint(p) || roadMask.GetPoint(p) || buildingMask.GetPoint(p) {
return nil, false // Collision detected
}
pixels = append(pixels, p)
@@ -480,7 +482,7 @@ func getBuildingPixels(center image.Point, size float64, shape string, isWater,
for y := center.Y - halfH; y <= center.Y+halfH; y++ {
for x := center.X - halfW; x <= center.X+halfW; x++ {
p := image.Point{X: x, Y: y}
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || isWater[p] || isRoad[p] || isBuilding[p] {
if p.X < 0 || p.Y < 0 || p.X >= width || p.Y >= height || waterMask.GetPoint(p) || roadMask.GetPoint(p) || buildingMask.GetPoint(p) {
return nil, false // Collision detected
}
pixels = append(pixels, p)