package d2isometricimg

import (
	
	
	
	
	
	
	

	
	
	
	
	
)

func nativeFontFamilies(,  *d2fonts.FontFamily) (d2fonts.FontFamily, d2fonts.FontFamily) {
	,  := d2fonts.SourceSansPro, d2fonts.SourceCodePro
	if  != nil && * != "" {
		 = *
	}
	if  != nil && * != "" {
		 = *
	}
	return , 
}

func nativeFontFamily( string, ,  d2fonts.FontFamily) (d2fonts.FontFamily, error) {
	,  = nativeFontFamilies(&, &)
	switch strings.ToLower(strings.TrimSpace()) {
	case "", "default":
		return , nil
	case "mono":
		return , nil
	case "sourcesanspro":
		return d2fonts.SourceSansPro, nil
	case "sourcecodepro":
		return d2fonts.SourceCodePro, nil
	case "handdrawn", "fuzzybubbles":
		return d2fonts.HandDrawn, nil
	}
	 := d2fonts.FontFamily()
	if ,  := d2fonts.FontFaces.Lookup(d2fonts.Font{Family: , Style: d2fonts.FONT_STYLE_REGULAR});  {
		return , nil
	}
	return "", fmt.Errorf("isometric text font family %q is not registered", )
}

func nativeSurfaceAssets( context.Context,  *d2scenebuild.AssetOptions) (*d2scenebuild.AssetOptions, error) {
	,  := newSurfaceIconPainter(, 1, )
	if  != nil {
		return nil, 
	}
	 := &d2scenebuild.AssetOptions{SVGImportLimits: .limits, SVGImportBudget: .remaining}
	// Only explicitly supplied resolvers may perform asset I/O. LaTeX itself
	// needs just the import limits and can render without any resolver.
	.Resolver = .resolver
	return , nil
}

// nativeSurfaceDocument retains the standard D2 scene for content that must
// preserve its complete 2D grammar before being projected onto a 3D surface.
func nativeSurfaceDocument( context.Context,  *d2target.Diagram,  *d2scenebuild.AssetOptions,  ...*d2scenebuild.FontFallbackOptions) (*d2scene.Document, error) {
	if  == nil ||  == nil {
		return nil, fmt.Errorf("native surface requires context and diagram")
	}
	if  == nil || .Resolver == nil {
		if  := nativeEmbeddedAssetsOnly();  != nil {
			return nil, 
		}
	}
	,  := nativeSurfaceAssets(, )
	if  != nil {
		return nil, 
	}
	 := int64(0)
	 := d2scenebuild.Options{
		Pad: &, MaxNodes: 200000, MaxPathCommands: 2000000,
		Assets:     ,
		LinkBudget: d2scenebuild.LinkBudget{MaxRegions: 20000, MaxStringBytes: maxTextSourceBytes},
		Fonts:      &d2scenebuild.FontFallbackOptions{MaxAssets: 96, MaxBytes: 64 << 20, MaxRunesPerText: maxLabelRunes, MaxTotalRunes: maxTextSourceBytes, MaxCoverageChecks: 8000000, MaxShapedGlyphs: 1000000, MaxShapingRuns: 200000, MaxFontFacesPerText: 8},
	}
	if .Config != nil {
		.ThemeID, .ThemeOverrides = .Config.ThemeID, .Config.ThemeOverrides
	}
	var  *d2scenebuild.FontFallbackOptions
	if len() > 0 {
		 = [0]
	}
	.Fonts,  = nativeSurfaceFonts()
	if  != nil {
		return nil, 
	}
	,  := d2scenebuild.Build(, , )
	if  != nil {
		return nil, 
	}
	if  = nativeDocumentGlyphCoverage(, );  != nil {
		return nil, 
	}
	return , nil
}

// rasterNativeSurfaceDocument never mutates the document. seconds is optional
// so static labels and deterministic animated panels share the same pipeline.
func rasterNativeSurfaceDocument( context.Context,  *d2scene.Document, ,  int,  ...float64) (*image.RGBA, error) {
	if  == nil ||  == nil ||  <= 0 ||  <= 0 ||  > 8192 ||  > 8192 || int64()*int64() > 8<<20 {
		return nil, fmt.Errorf("native surface has invalid document or texture dimensions")
	}
	 := 0.
	if len() > 0 {
		 = [0]
	}
	if !captionFinite() ||  < 0 ||  > float64(math.MaxInt64)/float64(time.Second) {
		return nil, fmt.Errorf("native surface has invalid frame time")
	}
	 := *
	.LogicalWidth, .LogicalHeight = float64(), float64()
	.ViewportFit, .ViewportAlign = d2scene.ViewportMeet, d2scene.ViewportAlignXMidYMid
	,  := d2raster.Render(, &, d2raster.FrameOptions{
		Scale: 1, Time: time.Duration( * float64(time.Second)), MaxWidth: , MaxHeight: , MaxPixels: int64() * int64(),
		MaxNodes: 200000, MaxDepth: 256, MaxPathCommands: 2000000,
		MaxTextRunesPerRun: maxLabelRunes, MaxTextCoverageChecks: 8000000, MaxTextShapingRuns: 200000, MaxFontFacesPerText: 8,
		MaxAnimationTracks: 20000, MaxAnimationKeyframes: 200000,
		MaxAssets: 20000, MaxAssetBytes: 128 << 20, MaxDecodedAssetBytes: 128 << 20, MaxImportDepth: 32,
		MaxOffscreenBytes: 256 << 20, MaxEvenOddClipWork: 64000000, MaxScanlineWork: 500000000,
	})
	if  != nil {
		return nil, 
	}
	 := image.NewRGBA(.Bounds())
	for  := 0;  < ; ++ {
		if  := .Err();  != nil {
			return nil, 
		}
		draw.Draw(, image.Rect(0, , , +1), , image.Pt(0, ), draw.Src)
	}
	if  := retainNativeVectorSurface(, , &);  != nil {
		return nil, 
	}
	return , nil
}

// Allocate by the actual surface aspect ratio. A long label can use a wide
// texture without reserving a mostly empty square or exceeding its share of
// the render's aggregate pixel budget.
func surfaceTextureDimensions(,  float64, ,  int) (int, int) {
	return surfaceTextureDimensionsAtDensity(, , , , 0)
}

// surfaceTextureDimensionsAtDensity matches a surface's projected output size.
// A small sampling margin avoids magnifying text at oblique angles. The same
// per-surface share and aggregate ceilings still apply at every output scale.
// Zero density preserves the original standalone painter allocation policy.
func surfaceTextureDimensionsAtDensity(,  float64, ,  int,  float64) (int, int) {
	,  := /max(, ), /max(, )
	 := min(float64(), math.Sqrt(float64()/(*)))
	if  > 0 && captionFinite() {
		 = min(, max(, )**1.5)
	}
	,  := max(1, int(math.Floor(*))), max(1, int(math.Floor(*)))
	if * >  {
		if  >=  {
			 = max(1, /)
		} else {
			 = max(1, /)
		}
	}
	return , 
}