mirror of
				https://bitbucket.org/s_l_teichmann/mtsatellite
				synced 2025-10-31 08:05:27 +01:00 
			
		
		
		
	Render transparent tiles if command line flag is set.
This commit is contained in:
		| @@ -48,6 +48,7 @@ func order(a, b int) (int, int) { | ||||
| func createBaseLevel( | ||||
| 	address string, | ||||
| 	xMin, zMin, xMax, zMax int, | ||||
| 	transparent bool, | ||||
| 	colorsFile, outDir string, | ||||
| 	numWorkers int) (err error) { | ||||
|  | ||||
| @@ -71,7 +72,7 @@ func createBaseLevel( | ||||
| 			return | ||||
| 		} | ||||
| 		done.Add(1) | ||||
| 		btc := common.NewBaseTileCreator(client, colors, baseDir, false) | ||||
| 		btc := common.NewBaseTileCreator(client, colors, transparent, baseDir, false) | ||||
| 		go createTiles(btc, jobs, &done) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -21,6 +21,7 @@ func main() { | ||||
| 		numWorkers    int | ||||
| 		skipBaseLevel bool | ||||
| 		skipPyramid   bool | ||||
| 		transparent   bool | ||||
| 	) | ||||
|  | ||||
| 	flag.IntVar(&port, "port", 6379, "port to of mtredisalize server") | ||||
| @@ -39,6 +40,8 @@ func main() { | ||||
| 	flag.BoolVar(&skipBaseLevel, "sb", false, "Do not generate base level tiles (shorthand)") | ||||
| 	flag.BoolVar(&skipPyramid, "skip-pyramid", false, "Do not generate pyramid tiles") | ||||
| 	flag.BoolVar(&skipPyramid, "sp", false, "Do not generate pyramid tiles (shorthand)") | ||||
| 	flag.BoolVar(&transparent, "transparent", false, "Render transparent blocks.") | ||||
| 	flag.BoolVar(&transparent, "t", false, "Render transparent blocks (shorthand).") | ||||
|  | ||||
| 	flag.Parse() | ||||
|  | ||||
| @@ -46,7 +49,12 @@ func main() { | ||||
| 	if !skipBaseLevel { | ||||
| 		address := fmt.Sprintf("%s:%d", host, port) | ||||
| 		if err = createBaseLevel( | ||||
| 			address, xMin, zMin, xMax, zMax, colorsFile, outDir, numWorkers); err != nil { | ||||
| 			address, | ||||
| 			xMin, zMin, xMax, zMax, | ||||
| 			transparent, | ||||
| 			colorsFile, | ||||
| 			outDir, | ||||
| 			numWorkers); err != nil { | ||||
| 			log.Fatalf("Creating base level tiles failed: %s", err) | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -23,6 +23,7 @@ func main() { | ||||
| 		colorsfile           string | ||||
| 		outfile              string | ||||
| 		shaded               bool | ||||
| 		transparent          bool | ||||
| 	) | ||||
|  | ||||
| 	flag.IntVar(&port, "port", 6379, "port to of mtredisalize server") | ||||
| @@ -41,6 +42,7 @@ func main() { | ||||
| 	flag.StringVar(&outfile, "output", "out.png", "image file of result") | ||||
| 	flag.StringVar(&outfile, "o", "out.png", "image file of result (shorthand)") | ||||
| 	flag.BoolVar(&shaded, "shaded", true, "draw relief") | ||||
| 	flag.BoolVar(&transparent, "transparent", false, "render transparent blocks") | ||||
|  | ||||
| 	flag.Parse() | ||||
|  | ||||
| @@ -70,7 +72,7 @@ func main() { | ||||
| 	q1x, q1y, q1z := int16(x), int16(y), int16(z) | ||||
| 	q2x, q2y, q2z := q1x+int16(width)-1, q1y+int16(depth)-1, q1z+int16(height)-1 | ||||
|  | ||||
| 	renderer := common.NewRenderer(width, height) | ||||
| 	renderer := common.NewRenderer(width, height, transparent) | ||||
| 	renderer.SetPos(q1x, q1z) | ||||
| 	yOrder := common.NewYOrder(renderer, 512) | ||||
|  | ||||
| @@ -106,7 +108,7 @@ func main() { | ||||
| 	if shaded { | ||||
| 		image = renderer.CreateShadedImage( | ||||
| 			16, 16, (width-2)*16, (height-2)*16, | ||||
| 			colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) | ||||
| 			colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) | ||||
| 	} else { | ||||
| 		image = renderer.CreateImage( | ||||
| 			colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) | ||||
|   | ||||
| @@ -17,14 +17,15 @@ import ( | ||||
|  | ||||
| func main() { | ||||
| 	var ( | ||||
| 		webPort    int | ||||
| 		webHost    string | ||||
| 		webDir     string | ||||
| 		mapDir     string | ||||
| 		redisPort  int | ||||
| 		redisHost  string | ||||
| 		colorsFile string | ||||
| 		workers    int | ||||
| 		webPort     int | ||||
| 		webHost     string | ||||
| 		webDir      string | ||||
| 		mapDir      string | ||||
| 		redisPort   int | ||||
| 		redisHost   string | ||||
| 		colorsFile  string | ||||
| 		workers     int | ||||
| 		transparent bool | ||||
| 	) | ||||
| 	flag.IntVar(&webPort, "web-port", 8808, "port of the web server") | ||||
| 	flag.IntVar(&webPort, "p", 8808, "port of the web server (shorthand)") | ||||
| @@ -41,6 +42,8 @@ func main() { | ||||
| 	flag.IntVar(&workers, "workers", 1, "number of workers to render tiles") | ||||
| 	flag.StringVar(&colorsFile, "colors", "colors.txt", "colors used to render map tiles.") | ||||
| 	flag.StringVar(&colorsFile, "c", "colors.txt", "colors used to render map tiles (shorthand).") | ||||
| 	flag.BoolVar(&transparent, "transparent", false, "Render transparent blocks.") | ||||
| 	flag.BoolVar(&transparent, "t", false, "Render transparent blocks (shorthand).") | ||||
|  | ||||
| 	flag.Parse() | ||||
|  | ||||
| @@ -56,7 +59,7 @@ func main() { | ||||
| 			log.Fatalf("ERROR: problem loading colors: %s", err) | ||||
| 		} | ||||
| 		redisAddress := fmt.Sprintf("%s:%d", redisHost, redisPort) | ||||
| 		tu := newTileUpdater(mapDir, redisAddress, colors, workers) | ||||
| 		tu := newTileUpdater(mapDir, redisAddress, colors, transparent, workers) | ||||
| 		go tu.doUpdates() | ||||
| 		router.Path("/update").Methods("POST").Handler(tu) | ||||
| 	} | ||||
|   | ||||
| @@ -26,6 +26,7 @@ type tileUpdater struct { | ||||
| 	redisAddress string | ||||
| 	colors       *common.Colors | ||||
| 	workers      int | ||||
| 	transparent  bool | ||||
| 	cond         *sync.Cond | ||||
| 	mu           sync.Mutex | ||||
| } | ||||
| @@ -56,12 +57,18 @@ func (c xz) parent() xzm { | ||||
| 		Mask: 1 << (zr<<1 | xr)} | ||||
| } | ||||
|  | ||||
| func newTileUpdater(mapDir, redisAddress string, colors *common.Colors, workers int) *tileUpdater { | ||||
| func newTileUpdater( | ||||
| 	mapDir, redisAddress string, | ||||
| 	colors *common.Colors, | ||||
| 	transparent bool, | ||||
| 	workers int) *tileUpdater { | ||||
|  | ||||
| 	tu := tileUpdater{ | ||||
| 		mapDir:       mapDir, | ||||
| 		redisAddress: redisAddress, | ||||
| 		changes:      map[xz]bool{}, | ||||
| 		colors:       colors, | ||||
| 		transparent:  transparent, | ||||
| 		workers:      workers} | ||||
| 	tu.cond = sync.NewCond(&tu.mu) | ||||
| 	return &tu | ||||
| @@ -113,7 +120,7 @@ func (tu *tileUpdater) doUpdates() { | ||||
| 				log.Printf("WARN: Cannot connect to redis server: %s", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			btc := common.NewBaseTileCreator(client, tu.colors, baseDir, true) | ||||
| 			btc := common.NewBaseTileCreator(client, tu.colors, tu.transparent, baseDir, true) | ||||
| 			done.Add(1) | ||||
| 			go updateBaseTiles(jobs, btc, &done) | ||||
| 		} | ||||
|   | ||||
| @@ -54,9 +54,10 @@ type BaseTileCreator struct { | ||||
| func NewBaseTileCreator( | ||||
| 	client *RedisClient, | ||||
| 	colors *Colors, | ||||
| 	transparent bool, | ||||
| 	baseDir string, | ||||
| 	update bool) *BaseTileCreator { | ||||
| 	renderer := NewRenderer(tileWidth, tileHeight) | ||||
| 	renderer := NewRenderer(tileWidth, tileHeight, transparent) | ||||
| 	return &BaseTileCreator{ | ||||
| 		client:   client, | ||||
| 		colors:   colors, | ||||
| @@ -118,7 +119,7 @@ func (btc *BaseTileCreator) CreateTile(x, z int16, i, j int) error { | ||||
|  | ||||
| 	image := btc.renderer.CreateShadedImage( | ||||
| 		16, 16, (tileWidth-2)*16, (tileHeight-2)*16, | ||||
| 		btc.colors.Colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) | ||||
| 		btc.colors, color.RGBA{R: 0xff, G: 0xff, B: 0xff, A: 0xff}) | ||||
|  | ||||
| 	path := filepath.Join(btc.baseDir, strconv.Itoa(i), fmt.Sprintf("%d.png", j)) | ||||
|  | ||||
|   | ||||
| @@ -115,8 +115,8 @@ func (colors *Colors) BlendColors(span *Span, col color.RGBA, pos int32) color.R | ||||
| 	} | ||||
| 	const scale = float32(1) / float32(100) | ||||
| 	for ; curr != nil; curr = curr.Next { | ||||
| 		// At least 20% attenuation + 5% extra for each depth meter. | ||||
| 		factor := float32(min(100, 20+(curr.To-curr.From)*5)) * scale | ||||
| 		// At least 35% attenuation + 5% extra for each depth meter. | ||||
| 		factor := float32(min(100, 35+(curr.To-curr.From)*5)) * scale | ||||
| 		col = BlendColor(colors.Colors[curr.Value], col, factor) | ||||
| 	} | ||||
| 	return col | ||||
|   | ||||
| @@ -27,6 +27,8 @@ type Renderer struct { | ||||
| 	RejectedBlocks    int | ||||
| 	SolidBlocks       int | ||||
| 	TransparentBlocks int | ||||
| 	spans             *SpanPool | ||||
| 	tBuffer           []*Span | ||||
| } | ||||
|  | ||||
| type YOrder struct { | ||||
| @@ -122,19 +124,29 @@ func (yo *YOrder) Pop() (x interface{}) { | ||||
| 	return x | ||||
| } | ||||
|  | ||||
| func NewRenderer(width, height int) (renderer *Renderer) { | ||||
| func NewRenderer(width, height int, transparent bool) (renderer *Renderer) { | ||||
| 	dim := width * height | ||||
| 	pixSize := dim * 16 * 16 | ||||
| 	yBuffer := make([]int32, pixSize) | ||||
| 	cBuffer := make([]int32, pixSize) | ||||
| 	yMin := make([]int32, dim) | ||||
|  | ||||
| 	var tBuffer []*Span | ||||
| 	var spans *SpanPool | ||||
|  | ||||
| 	if transparent { | ||||
| 		tBuffer = make([]*Span, pixSize) | ||||
| 		spans = NewSpanPool() | ||||
| 	} | ||||
|  | ||||
| 	renderer = &Renderer{ | ||||
| 		width:   width, | ||||
| 		height:  height, | ||||
| 		yBuffer: yBuffer, | ||||
| 		cBuffer: cBuffer, | ||||
| 		yMin:    yMin} | ||||
| 		yMin:    yMin, | ||||
| 		tBuffer: tBuffer, | ||||
| 		spans:   spans} | ||||
|  | ||||
| 	renderer.Reset() | ||||
| 	return | ||||
| @@ -153,6 +165,15 @@ func (r *Renderer) Reset() { | ||||
| 	for i, n := 0, len(r.yMin); i < n; i++ { | ||||
| 		r.yMin[i] = math.MinInt32 | ||||
| 	} | ||||
|  | ||||
| 	if r.tBuffer != nil { | ||||
| 		for i, t := range r.tBuffer { | ||||
| 			if t != nil { | ||||
| 				r.spans.FreeAll(t) | ||||
| 				r.tBuffer[i] = nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (r *Renderer) IsFilled() bool { | ||||
| @@ -189,37 +210,64 @@ func (r *Renderer) RenderBlock(block *Block, colors *Colors) (err error) { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if db.Transparent { | ||||
| 		r.TransparentBlocks++ | ||||
| 	} else { | ||||
| 		r.SolidBlocks++ | ||||
| 	} | ||||
|  | ||||
| 	w := r.width << 4 | ||||
| 	ofs := int(bz)*w<<4 + int(bx)<<4 | ||||
| 	yB := r.yBuffer | ||||
|  | ||||
| 	yMin := int32(math.MaxInt32) | ||||
| 	for z := 0; z < 16; z++ { | ||||
| 		for x := 0; x < 16; x++ { | ||||
| 			currentY := yB[ofs] | ||||
| 			if currentY < blockY { | ||||
| 				for y := 15; y >= 0; y-- { | ||||
| 					if c, ok := db.Content(x, y, z); ok { | ||||
| 						r.cBuffer[ofs] = c | ||||
| 						currentY = blockY + int32(y) | ||||
| 						yB[ofs] = currentY | ||||
| 						break | ||||
|  | ||||
| 	if db.Transparent && r.tBuffer != nil { | ||||
| 		r.TransparentBlocks++ | ||||
|  | ||||
| 		for z := 0; z < 16; z++ { | ||||
| 			for x := 0; x < 16; x++ { | ||||
| 				currentY := yB[ofs] | ||||
| 				if currentY < blockY { | ||||
| 					for y := 15; y >= 0; y-- { | ||||
| 						if c, ok := db.Content(x, y, z); ok { | ||||
| 							currentY = blockY + int32(y) | ||||
|  | ||||
| 							if colors.IsTransparent(c) { | ||||
| 								r.tBuffer[ofs] = r.spans.Insert(r.tBuffer[ofs], currentY, c) | ||||
| 							} else { | ||||
| 								r.cBuffer[ofs] = c | ||||
| 								yB[ofs] = currentY | ||||
| 								break | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				if currentY < yMin { | ||||
| 					yMin = currentY | ||||
| 				} | ||||
| 				ofs++ | ||||
| 			} | ||||
| 			if currentY < yMin { | ||||
| 				yMin = currentY | ||||
| 			} | ||||
| 			ofs++ | ||||
| 			ofs += w - 16 | ||||
| 		} | ||||
|  | ||||
| 	} else { | ||||
| 		r.SolidBlocks++ | ||||
| 		for z := 0; z < 16; z++ { | ||||
| 			for x := 0; x < 16; x++ { | ||||
| 				currentY := yB[ofs] | ||||
| 				if currentY < blockY { | ||||
| 					for y := 15; y >= 0; y-- { | ||||
| 						if c, ok := db.Content(x, y, z); ok { | ||||
| 							r.cBuffer[ofs] = c | ||||
| 							currentY = blockY + int32(y) | ||||
| 							yB[ofs] = currentY | ||||
| 							break | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				if currentY < yMin { | ||||
| 					yMin = currentY | ||||
| 				} | ||||
| 				ofs++ | ||||
| 			} | ||||
| 			ofs += w - 16 | ||||
| 		} | ||||
| 		ofs += w - 16 | ||||
| 	} | ||||
|  | ||||
| 	r.yMin[pos] = yMin | ||||
|  | ||||
| 	return | ||||
| @@ -349,13 +397,15 @@ func safeColor(x int32) uint8 { | ||||
|  | ||||
| func (r *Renderer) CreateShadedImage( | ||||
| 	xOfs, zOfs, width, height int, | ||||
| 	colors []color.RGBA, background color.RGBA) *image.RGBA { | ||||
| 	cols *Colors, background color.RGBA) *image.RGBA { | ||||
|  | ||||
| 	image := image.NewRGBA(image.Rect(0, 0, width, height)) | ||||
|  | ||||
| 	pw := r.width << 4 | ||||
|  | ||||
| 	ofs, numCols := zOfs*pw+xOfs, int32(len(colors)) | ||||
| 	cs := cols.Colors | ||||
|  | ||||
| 	ofs, numCols := zOfs*pw+xOfs, int32(len(cs)) | ||||
|  | ||||
| 	stride := pw - width | ||||
|  | ||||
| @@ -365,42 +415,91 @@ func (r *Renderer) CreateShadedImage( | ||||
|  | ||||
| 	pix := image.Pix | ||||
|  | ||||
| 	for z := height - 1; z >= 0; z-- { | ||||
| 		for x := 0; x < width; x++ { | ||||
| 			colIdx := r.cBuffer[ofs] | ||||
| 			if colIdx < 0 || colIdx >= numCols { | ||||
| 				pix[iofs] = background.R | ||||
| 				pix[iofs+1] = background.G | ||||
| 				pix[iofs+2] = background.B | ||||
| 				pix[iofs+3] = 0xff | ||||
| 			} else { | ||||
| 				var y, y1, y2 int32 | ||||
| 				y = r.yBuffer[ofs] | ||||
| 				if x == 0 { | ||||
| 					y1 = y | ||||
| 	if r.tBuffer != nil { // Fast path for transparent images. | ||||
| 		for z := height - 1; z >= 0; z-- { | ||||
| 			for x := 0; x < width; x++ { | ||||
| 				colIdx := r.cBuffer[ofs] | ||||
| 				if colIdx < 0 || colIdx >= numCols { | ||||
| 					pix[iofs] = background.R | ||||
| 					pix[iofs+1] = background.G | ||||
| 					pix[iofs+2] = background.B | ||||
| 					pix[iofs+3] = 0xff | ||||
| 				} else { | ||||
| 					y1 = r.yBuffer[ofs-1] | ||||
| 					var y, y1, y2 int32 | ||||
| 					y = r.yBuffer[ofs] | ||||
| 					if x == 0 { | ||||
| 						y1 = y | ||||
| 					} else { | ||||
| 						y1 = r.yBuffer[ofs-1] | ||||
| 					} | ||||
| 					if z == 0 { | ||||
| 						y2 = y | ||||
| 					} else { | ||||
| 						y2 = r.yBuffer[ofs+pw] | ||||
| 					} | ||||
| 					d := ((y - y1) + (y - y2)) * 12 | ||||
| 					if d > 36 { | ||||
| 						d = 36 | ||||
| 					} | ||||
| 					col := cs[colIdx] | ||||
| 					col = color.RGBA{ | ||||
| 						R: safeColor(int32(col.R) + d), | ||||
| 						G: safeColor(int32(col.G) + d), | ||||
| 						B: safeColor(int32(col.B) + d), | ||||
| 						A: 0xff} | ||||
| 					if r.tBuffer[ofs] != nil { | ||||
| 						col = cols.BlendColors(r.tBuffer[ofs], col, y) | ||||
| 					} | ||||
| 					pix[iofs] = col.R | ||||
| 					pix[iofs+1] = col.G | ||||
| 					pix[iofs+2] = col.B | ||||
| 					pix[iofs+3] = col.A | ||||
| 				} | ||||
| 				if z == 0 { | ||||
| 					y2 = y | ||||
| 				} else { | ||||
| 					y2 = r.yBuffer[ofs+pw] | ||||
| 				} | ||||
| 				d := ((y - y1) + (y - y2)) * 12 | ||||
| 				if d > 36 { | ||||
| 					d = 36 | ||||
| 				} | ||||
| 				col := colors[colIdx] | ||||
| 				pix[iofs] = safeColor(int32(col.R) + d) | ||||
| 				pix[iofs+1] = safeColor(int32(col.G) + d) | ||||
| 				pix[iofs+2] = safeColor(int32(col.B) + d) | ||||
| 				pix[iofs+3] = 0xff | ||||
| 				iofs += 4 | ||||
| 				ofs++ | ||||
| 			} | ||||
| 			iofs += 4 | ||||
| 			ofs++ | ||||
| 			ofs += stride | ||||
| 			iofs -= istride | ||||
| 		} | ||||
|  | ||||
| 	} else { // Solid images. | ||||
| 		for z := height - 1; z >= 0; z-- { | ||||
| 			for x := 0; x < width; x++ { | ||||
| 				colIdx := r.cBuffer[ofs] | ||||
| 				if colIdx < 0 || colIdx >= numCols { | ||||
| 					pix[iofs] = background.R | ||||
| 					pix[iofs+1] = background.G | ||||
| 					pix[iofs+2] = background.B | ||||
| 					pix[iofs+3] = 0xff | ||||
| 				} else { | ||||
| 					var y, y1, y2 int32 | ||||
| 					y = r.yBuffer[ofs] | ||||
| 					if x == 0 { | ||||
| 						y1 = y | ||||
| 					} else { | ||||
| 						y1 = r.yBuffer[ofs-1] | ||||
| 					} | ||||
| 					if z == 0 { | ||||
| 						y2 = y | ||||
| 					} else { | ||||
| 						y2 = r.yBuffer[ofs+pw] | ||||
| 					} | ||||
| 					d := ((y - y1) + (y - y2)) * 12 | ||||
| 					if d > 36 { | ||||
| 						d = 36 | ||||
| 					} | ||||
| 					col := cs[colIdx] | ||||
| 					pix[iofs] = safeColor(int32(col.R) + d) | ||||
| 					pix[iofs+1] = safeColor(int32(col.G) + d) | ||||
| 					pix[iofs+2] = safeColor(int32(col.B) + d) | ||||
| 					pix[iofs+3] = 0xff | ||||
| 				} | ||||
| 				iofs += 4 | ||||
| 				ofs++ | ||||
| 			} | ||||
| 			ofs += stride | ||||
| 			iofs -= istride | ||||
| 		} | ||||
| 		ofs += stride | ||||
| 		iofs -= istride | ||||
| 	} | ||||
| 	return image | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user