package d2isometricimg
import (
"fmt"
"math"
)
type svgPaintCover struct {
batches []*svgPaintBatch
polygons [][]svgPoint
first int
written bool
}
func svgPreparePaintCovers(batches []*svgPaintBatch ) map [*svgPaintBatch ]*svgPaintCover {
type key struct {
material *Material
decal bool
texture bool
}
byMaterial := make (map [key ]*svgPaintCover )
for _ , batch := range batches {
material := batch .triangle .Material
if material == nil || len (batch .polygons ) == 0 {
continue
}
if batch .texture && (!material .svgSolidTexture || batch .triangle .NoDepthWrite || material .Multiply ) {
continue
}
k := key {material , batch .triangle .NoDepthWrite , batch .texture }
cover := byMaterial [k ]
if cover == nil {
cover = &svgPaintCover {first : batch .first }
byMaterial [k ] = cover
}
cover .batches = append (cover .batches , batch )
cover .polygons = append (cover .polygons , batch .polygons ...)
}
result := make (map [*svgPaintBatch ]*svgPaintCover )
for _ , cover := range byMaterial {
if len (cover .batches ) < 2 {
continue
}
for _ , batch := range cover .batches {
result [batch ] = cover
}
}
return result
}
func writeSVGPaintCover(w *nativeSVGWriter , cover *svgPaintCover , camera rasterCamera ) {
if cover .written || w .err != nil {
return
}
cover .written = true
var points []svgPoint
for _ , polygon := range cover .polygons {
points = append (points , polygon ...)
}
box := svgPolygonBox (points )
box .minX , box .minY , box .maxX , box .maxY = box .minX -1 , box .minY -1 , box .maxX +1 , box .maxY +1
name := fmt .Sprintf ("paint-cover-%d" , cover .first )
fills := make ([]string , len (cover .batches ))
for i , batch := range cover .batches {
if batch .texture {
continue
}
fills [i ] = batch .color
if fills [i ] == "" {
fills [i ] = writeSVGFaceGradient (w , batch , -batch .first -1 , camera )
}
if w .err != nil {
return
}
}
w .write (`<defs><pattern id="%s" patternUnits="userSpaceOnUse" x="%s" y="%s" width="%s" height="%s" viewBox="%s %s %s %s" preserveAspectRatio="none">` , name , svgNumber (box .minX ), svgNumber (box .minY ), svgNumber (box .maxX -box .minX ), svgNumber (box .maxY -box .minY ), svgNumber (box .minX ), svgNumber (box .minY ), svgNumber (box .maxX -box .minX ), svgNumber (box .maxY -box .minY ))
for i , batch := range cover .batches {
if batch .texture {
part := *batch
material := *part .triangle .Material
material .Color .A , material .Multiply = 255 , false
part .triangle .Material , part .cover = &material , nil
part .polygons = make ([][]svgPoint , len (batch .polygons ))
for j , polygon := range batch .polygons {
part .polygons [j ] = svgExpandCoverPolygon (polygon , .4 )
}
writeSVGBatch (w , &part , -batch .first -1 , camera )
continue
}
w .write (`<path d="%s" fill="%s" stroke="%s" stroke-width="0.8" stroke-linejoin="round"/>` , svgPolygonPath (batch .polygons ), fills [i ], fills [i ])
}
w .write (`</pattern></defs>` )
material := cover .batches [0 ].triangle .Material
blend := ""
if material .Multiply {
blend = ` style="mix-blend-mode:multiply"`
}
w .write (`<path d="%s" fill="url(#%s)" fill-opacity="%s"%s/>` , svgPolygonPath (cover .polygons ), name , svgNumber (float64 (material .Color .A )/255 ), blend )
}
func svgExpandCoverPolygon(polygon []svgPoint , width float64 ) []svgPoint {
if len (polygon ) < 3 || width <= 0 {
return polygon
}
box := svgPolygonBox (polygon )
points := []svgPoint {
{box .minX - width , box .minY - width , 0 },
{box .maxX + width , box .minY - width , 0 },
{box .maxX + width , box .maxY + width , 0 },
{box .minX - width , box .maxY + width , 0 },
}
sign := 1.
if svgPolygonArea (polygon ) < 0 {
sign = -1
}
for i , a := range polygon {
b := polygon [(i +1 )%len (polygon )]
dx , dy := b .x -a .x , b .y -a .y
length := math .Hypot (dx , dy )
if length < 1e-12 {
continue
}
distance := svgEdgeDistance (a , b )
points , _ = svgSplitPolygon (points , func (p svgPoint ) float64 {
return sign *distance (p )/length + width
})
}
return points
}
The pages are generated with Golds v0.8.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .