package d2isometricimg

import (
	
	
	
	
	
	

	

	
	
	libcolor 
)

const nativeGradientTextureSize = 256
const maxNativeGradientPixels = 8 << 20

func nativePaintDocument( d2scene.Paint) *d2scene.Document {
	 := d2scene.Box{Width: nativeGradientTextureSize, Height: nativeGradientTextureSize}
	return d2scene.NewDocument(, d2scene.NewNode(d2scene.Rect{Box: , Fill: }))
}

func ( *meshBuilder) ( string) *image.RGBA {
	if .err != nil {
		return nil
	}
	if  := .gradientTextures[];  != nil {
		return 
	}
	if len(.gradientTextures) >= maxNativeGradientPixels/(nativeGradientTextureSize*nativeGradientTextureSize) {
		.err = fmt.Errorf("isometric gradients exceed %d texture pixels", maxNativeGradientPixels)
		return nil
	}
	,  := scenepaint.Gradient()
	if  != nil {
		.err = 
		return nil
	}
	,  := rasterNativeSurfaceDocument(.ctx, nativePaintDocument(), nativeGradientTextureSize, nativeGradientTextureSize)
	if  != nil {
		.err = 
		return nil
	}
	if .gradientTextures == nil {
		.gradientTextures = make(map[string]*image.RGBA)
	}
	.gradientTextures[] = 
	return 
}

// A geometric stroke is one paint operation even when tessellation splits it
// into many ribbons. Map its complete visible footprint into one gradient,
// retaining the same mapping across dashes, joins and arrowheads. Projecting
// onto a common plane also gives upright side ink a nondegenerate UV mapping.
func ( *meshBuilder) () {
	type  struct{ , , ,  float64 }
	 := make(map[*Material])
	 := nativeCameraAxes().direction
	 := func( Vec) Vec { return nsub(, nmul(, .Y/.Y)) }
	for ,  := range .triangles {
		if %1024 == 0 {
			if  := .ctx.Err();  != nil {
				.err = 
				return
			}
		}
		 := .Material
		if  == nil || .gradient == "" || .Texture != nil {
			continue
		}
		,  := []
		if ! {
			 = {math.Inf(1), math.Inf(1), math.Inf(-1), math.Inf(-1)}
		}
		for ,  := range .V {
			 := (.Position)
			. = min(., .X)
			. = min(., .Z)
			. = max(., .X)
			. = max(., .Z)
		}
		[] = 
	}
	for  := range  {
		 := .gradientTexture(.gradient)
		if .err != nil {
			return
		}
		.Texture, .Vector = , nativeVectorForTexture(.ctx, )
	}
	for  := range .triangles {
		if %1024 == 0 {
			if  := .ctx.Err();  != nil {
				.err = 
				return
			}
		}
		 := &.triangles[]
		,  := [.Material]
		if ! {
			continue
		}
		for  := range .V {
			 := (.V[].Position)
			.V[].U = (.X - .) / max(1e-9, .-.)
			.V[].V = (.Z - .) / max(1e-9, .-.)
		}
	}
}

type nativeGradientBackgroundKey struct{}

func nativeGradientBackgroundContext( context.Context,  *image.RGBA) context.Context {
	if  == nil {
		return 
	}
	return context.WithValue(, nativeGradientBackgroundKey{}, )
}

// Keep the ordinary opaque presentation background beneath translucent stops.
func nativeGradientBackground( *image.RGBA, ,  float64,  color.NRGBA) color.NRGBA {
	, , ,  := rasterTexture(, , )
	return color.NRGBA{uint8(math.Round((* + float64(.R)/255*(1-)) * 255)), uint8(math.Round((* + float64(.G)/255*(1-)) * 255)), uint8(math.Round((* + float64(.B)/255*(1-)) * 255)), 255}
}

func nativeLabelBackgroundPaint( labelTextStyle) d2scene.Paint {
	if .BackgroundPaint != nil {
		return .BackgroundPaint
	}
	if .Background != nil {
		return d2scene.SolidPaint{Color: *.Background}
	}
	return nil
}

func nativeLabelBackground( context.Context,  labelTextStyle, ,  int) (image.Image, error) {
	if .BackgroundPaint == nil {
		if .Background != nil {
			return image.NewUniform(*.Background), nil
		}
		return nil, nil
	}
	 := d2scene.Box{Width: float64(), Height: float64()}
	 := d2scene.NewDocument(, d2scene.NewNode(d2scene.Rect{Box: , Fill: .BackgroundPaint}))
	return rasterNativeSurfaceDocument(, , , )
}

// Scalar decisions (contrast, fully transparent bodies, opaque rims) need a
// representative color, while the actual geometry retains the complete paint.
func nativeGradientSummary( string) (color.NRGBA, bool) {
	,  := scenepaint.Gradient()
	if  != nil {
		return color.NRGBA{}, false
	}
	var  []d2scene.GradientStop
	switch p := .(type) {
	case d2scene.LinearGradient:
		 = .Stops
	case d2scene.RadialGradient:
		 = .Stops
	}
	if len() == 0 {
		return color.NRGBA{}, false
	}
	var  [4]float64
	,  := true, true
	for ,  := range  {
		 := .Color
		[0] += float64(.R)
		[1] += float64(.G)
		[2] += float64(.B)
		[3] += float64(.A)
		 =  && .A == 255
		 =  && .A == 0
	}
	for  := range  {
		[] /= float64(len())
	}
	 := uint8(math.Round([3]))
	if ! &&  == 255 {
		 = 254
	}
	if ! &&  == 0 {
		 = 1
	}
	return color.NRGBA{uint8(math.Round([0])), uint8(math.Round([1])), uint8(math.Round([2])), }, true
}

// Organizational container washes preserve gradient stops and geometry while
// applying the same presentation opacity already used for solid source fills.
func nativeGradientOpacity( string,  float64) (string, error) {
	,  := libcolor.ParseGradient()
	if  != nil {
		return "", 
	}
	 := make([]string, 0, len(.ColorStops)+1)
	if .Direction != "" {
		 = append(, .Direction)
	}
	for ,  := range .ColorStops {
		,  := csscolorparser.Parse(.Color)
		if  != nil {
			return "", 
		}
		, , ,  := .RGBA255()
		 := richColor(color.NRGBA{, , , uint8(math.Round(float64() * ))})
		if .Position != "" {
			 += " " + .Position
		}
		 = append(, )
	}
	return .Type + "-gradient(" + strings.Join(, ",") + ")", nil
}