Layers API

Multi-layer compositing system with blend modes and advanced effects.

Layer Manager

Creating Layer Manager

// Create layer manager
layerManager := advancegg.NewLayerManager(800, 600)

// Add layers
background := layerManager.AddLayer("background")
content := layerManager.AddLayer("content")
overlay := layerManager.AddLayer("overlay")

// Each layer is a full Context that you can draw on
background.SetRGB(0.2, 0.2, 0.4)
background.Clear()

content.SetRGB(1, 0.5, 0)
content.DrawCircle(400, 300, 100)
content.Fill()

overlay.SetRGBA(1, 1, 1, 0.5)
overlay.DrawString("Overlay Text", 350, 320)

Layer Operations

// Get layer by name
layer := layerManager.GetLayer("content")

// Remove layer
layerManager.RemoveLayer("overlay")

// Duplicate layer
layerManager.DuplicateLayer("content", "content_copy")

// Reorder layers
layerManager.MoveLayerUp("background")
layerManager.MoveLayerDown("overlay")
layerManager.MoveLayerToTop("content")
layerManager.MoveLayerToBottom("background")

// Get layer list
layerNames := layerManager.GetLayerNames()
for _, name := range layerNames {
    fmt.Printf("Layer: %s\n", name)
}

Layer Properties

Opacity

// Set layer opacity (0.0 to 1.0)
layerManager.SetLayerOpacity("content", 0.8)    // 80% opacity
layerManager.SetLayerOpacity("overlay", 0.5)    // 50% opacity

// Get layer opacity
opacity := layerManager.GetLayerOpacity("content")
fmt.Printf("Layer opacity: %f\n", opacity)

// Fade layer in/out
for i := 0; i <= 100; i++ {
    opacity := float64(i) / 100.0
    layerManager.SetLayerOpacity("content", opacity)
    // Render frame
}

Visibility

// Show/hide layers
layerManager.SetLayerVisible("background", true)
layerManager.SetLayerVisible("overlay", false)

// Toggle visibility
layerManager.ToggleLayerVisibility("content")

// Check if layer is visible
visible := layerManager.IsLayerVisible("content")
fmt.Printf("Layer visible: %v\n", visible)

Locking

// Lock/unlock layers
layerManager.SetLayerLocked("background", true)  // Prevent modifications
layerManager.SetLayerLocked("content", false)    // Allow modifications

// Check if layer is locked
locked := layerManager.IsLayerLocked("background")
fmt.Printf("Layer locked: %v\n", locked)

Blend Modes

Basic Blend Modes

// Set blend mode for layer
layerManager.SetLayerBlendMode("content", advancegg.BlendModeNormal)     // Default
layerManager.SetLayerBlendMode("overlay", advancegg.BlendModeMultiply)
layerManager.SetLayerBlendMode("highlight", advancegg.BlendModeScreen)

// Available blend modes:
// Normal, Multiply, Screen, Overlay, SoftLight, HardLight,
// ColorDodge, ColorBurn, Darken, Lighten, Difference, Exclusion

Advanced Blend Modes

// Color blend modes
layerManager.SetLayerBlendMode("color", advancegg.BlendModeColor)
layerManager.SetLayerBlendMode("hue", advancegg.BlendModeHue)
layerManager.SetLayerBlendMode("saturation", advancegg.BlendModeSaturation)
layerManager.SetLayerBlendMode("luminosity", advancegg.BlendModeLuminosity)

// Special effects
layerManager.SetLayerBlendMode("glow", advancegg.BlendModeLinearDodge)
layerManager.SetLayerBlendMode("shadow", advancegg.BlendModeLinearBurn)
layerManager.SetLayerBlendMode("vivid", advancegg.BlendModeVividLight)
layerManager.SetLayerBlendMode("pin", advancegg.BlendModePinLight)

Custom Blend Functions

// Define custom blend function
customBlend := func(base, overlay color.Color) color.Color {
    br, bg, bb, ba := base.RGBA()
    or, og, ob, oa := overlay.RGBA()
    
    // Custom blending logic
    r := (br + or) / 2
    g := (bg + og) / 2
    b := (bb + ob) / 2
    a := (ba + oa) / 2
    
    return color.RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}

// Register and use custom blend mode
advancegg.RegisterBlendMode("custom", customBlend)
layerManager.SetLayerBlendMode("special", "custom")

Layer Effects

Drop Shadow

// Add drop shadow to layer
shadow := advancegg.DropShadowEffect{
    OffsetX:   5,
    OffsetY:   5,
    Blur:      10,
    Color:     color.RGBA{0, 0, 0, 128},
    Spread:    2,
}
layerManager.AddLayerEffect("content", shadow)

// Inner shadow
innerShadow := advancegg.InnerShadowEffect{
    OffsetX:   -2,
    OffsetY:   -2,
    Blur:      5,
    Color:     color.RGBA{0, 0, 0, 100},
}
layerManager.AddLayerEffect("content", innerShadow)

Glow Effects

// Outer glow
outerGlow := advancegg.OuterGlowEffect{
    Size:      15,
    Color:     color.RGBA{255, 255, 0, 200},
    Spread:    5,
    Quality:   advancegg.EffectQualityHigh,
}
layerManager.AddLayerEffect("content", outerGlow)

// Inner glow
innerGlow := advancegg.InnerGlowEffect{
    Size:      10,
    Color:     color.RGBA{255, 255, 255, 150},
    Source:    advancegg.GlowSourceCenter,
}
layerManager.AddLayerEffect("content", innerGlow)

Stroke Effects

// Stroke (outline)
stroke := advancegg.StrokeEffect{
    Size:      3,
    Color:     color.RGBA{255, 0, 0, 255},
    Position:  advancegg.StrokePositionOutside,
    FillType:  advancegg.StrokeFillColor,
}
layerManager.AddLayerEffect("content", stroke)

// Gradient stroke
gradientStroke := advancegg.StrokeEffect{
    Size:      5,
    Position:  advancegg.StrokePositionCenter,
    FillType:  advancegg.StrokeFillGradient,
    Gradient:  myGradient,
}
layerManager.AddLayerEffect("content", gradientStroke)

Bevel and Emboss

// Bevel effect
bevel := advancegg.BevelEffect{
    Style:         advancegg.BevelStyleInner,
    Technique:     advancegg.BevelTechniqueSmoothChisel,
    Depth:         5,
    Direction:     advancegg.BevelDirectionUp,
    Size:          10,
    Soften:        2,
    Angle:         120,
    Altitude:      30,
    HighlightMode: advancegg.BlendModeScreen,
    ShadowMode:    advancegg.BlendModeMultiply,
}
layerManager.AddLayerEffect("content", bevel)

Layer Masks

Creating Masks

// Create layer mask
mask := layerManager.CreateLayerMask("content")

// Draw on mask (white = visible, black = hidden)
mask.SetRGB(1, 1, 1)  // White
mask.DrawCircle(400, 300, 100)
mask.Fill()

// Gradient mask
mask.SetRGB(0, 0, 0)  // Black
mask.Clear()
gradient := advancegg.NewLinearGradient(0, 0, 800, 0)
gradient.AddColorStop(0, color.RGBA{255, 255, 255, 255})  // White (visible)
gradient.AddColorStop(1, color.RGBA{0, 0, 0, 255})        // Black (hidden)
mask.SetFillStyle(gradient)
mask.DrawRectangle(0, 0, 800, 600)
mask.Fill()

Mask Operations

// Enable/disable mask
layerManager.SetLayerMaskEnabled("content", true)
layerManager.SetLayerMaskEnabled("content", false)

// Invert mask
layerManager.InvertLayerMask("content")

// Apply mask (merge with layer)
layerManager.ApplyLayerMask("content")

// Delete mask
layerManager.DeleteLayerMask("content")

// Mask from selection
selection := advancegg.CreateSelection(selectionPath)
layerManager.CreateLayerMaskFromSelection("content", selection)

Vector Masks

// Create vector mask from path
path := advancegg.NewPath2D()
path.MoveTo(100, 100)
path.LineTo(700, 100)
path.LineTo(700, 500)
path.LineTo(100, 500)
path.ClosePath()

vectorMask := layerManager.CreateVectorMask("content", path)

// Feather vector mask
vectorMask.SetFeather(10) // 10 pixel feather

// Vector mask operations
vectorMask.Subtract(anotherPath)
vectorMask.Intersect(anotherPath)
vectorMask.Add(anotherPath)
vectorMask.Exclude(anotherPath)

Layer Groups

Creating Groups

// Create layer group
group := layerManager.CreateLayerGroup("UI Elements")

// Add layers to group
layerManager.AddLayerToGroup("button", "UI Elements")
layerManager.AddLayerToGroup("text", "UI Elements")
layerManager.AddLayerToGroup("icon", "UI Elements")

// Group properties
layerManager.SetGroupOpacity("UI Elements", 0.8)
layerManager.SetGroupBlendMode("UI Elements", advancegg.BlendModeMultiply)
layerManager.SetGroupVisible("UI Elements", false)

// Nested groups
subGroup := layerManager.CreateLayerGroup("Buttons", "UI Elements")
layerManager.AddLayerToGroup("primary_button", "Buttons")
layerManager.AddLayerToGroup("secondary_button", "Buttons")

Group Operations

// Collapse/expand group
layerManager.SetGroupCollapsed("UI Elements", true)

// Duplicate group
layerManager.DuplicateGroup("UI Elements", "UI Elements Copy")

// Merge group
layerManager.MergeGroup("UI Elements")

// Ungroup
layerManager.Ungroup("UI Elements")

// Get group layers
groupLayers := layerManager.GetGroupLayers("UI Elements")
for _, layerName := range groupLayers {
    fmt.Printf("Group layer: %s\n", layerName)
}

Compositing

Flattening Layers

// Flatten all layers
result := layerManager.Flatten()

// Flatten specific layers
layersToFlatten := []string{"background", "content"}
flattened := layerManager.FlattenLayers(layersToFlatten)

// Flatten visible layers only
visibleFlattened := layerManager.FlattenVisible()

// Flatten with options
options := advancegg.FlattenOptions{
    IncludeHidden:   false,
    PreserveAlpha:   true,
    BackgroundColor: color.RGBA{255, 255, 255, 255},
}
customFlattened := layerManager.FlattenWithOptions(options)

Export Options

// Export individual layers
for _, layerName := range layerManager.GetLayerNames() {
    layer := layerManager.GetLayer(layerName)
    layer.SavePNG(fmt.Sprintf("layer_%s.png", layerName))
}

// Export with transparency
layerManager.ExportLayerPNG("content", "content_with_alpha.png", true)

// Export layer bounds only
bounds := layerManager.GetLayerBounds("content")
cropped := layerManager.ExportLayerBounds("content", bounds)

// Export as PSD (Photoshop format)
layerManager.ExportPSD("project.psd")

Complete Examples

Complex Layer Composition

package main

import (
    "image/color"
    "github.com/GrandpaEJ/advancegg"
)

func main() {
    // Create layer manager
    lm := advancegg.NewLayerManager(1200, 800)
    
    // Background layer with gradient
    bg := lm.AddLayer("background")
    bgGradient := advancegg.NewLinearGradient(0, 0, 0, 800)
    bgGradient.AddColorStop(0, color.RGBA{20, 30, 60, 255})
    bgGradient.AddColorStop(1, color.RGBA{60, 30, 20, 255})
    bg.SetFillStyle(bgGradient)
    bg.DrawRectangle(0, 0, 1200, 800)
    bg.Fill()
    
    // Mountains layer
    mountains := lm.AddLayer("mountains")
    mountains.SetRGBA(0.1, 0.2, 0.3, 0.8)
    drawMountains(mountains)
    lm.SetLayerBlendMode("mountains", advancegg.BlendModeMultiply)
    
    // Stars layer
    stars := lm.AddLayer("stars")
    drawStars(stars, 100)
    lm.SetLayerOpacity("stars", 0.7)
    
    // Moon layer with glow effect
    moon := lm.AddLayer("moon")
    moon.SetRGB(1, 1, 0.9)
    moon.DrawCircle(900, 150, 60)
    moon.Fill()
    
    // Add glow effect to moon
    glow := advancegg.OuterGlowEffect{
        Size:    30,
        Color:   color.RGBA{255, 255, 200, 100},
        Spread:  10,
    }
    lm.AddLayerEffect("moon", glow)
    
    // Text layer with effects
    text := lm.AddLayer("title")
    text.LoadFontFace("fonts/arial-bold.ttf", 48)
    text.SetRGB(1, 1, 1)
    text.DrawStringAnchored("Starry Night", 600, 400, 0.5, 0.5)
    
    // Add text effects
    shadow := advancegg.DropShadowEffect{
        OffsetX: 3,
        OffsetY: 3,
        Blur:    8,
        Color:   color.RGBA{0, 0, 0, 150},
    }
    lm.AddLayerEffect("title", shadow)
    
    stroke := advancegg.StrokeEffect{
        Size:     2,
        Color:    color.RGBA{100, 100, 200, 255},
        Position: advancegg.StrokePositionOutside,
    }
    lm.AddLayerEffect("title", stroke)
    
    // Create layer group for UI
    ui := lm.CreateLayerGroup("UI")
    
    // Watermark layer
    watermark := lm.AddLayer("watermark")
    lm.AddLayerToGroup("watermark", "UI")
    watermark.SetRGBA(1, 1, 1, 0.3)
    watermark.LoadFontFace("fonts/arial.ttf", 16)
    watermark.DrawStringAnchored("© AdvanceGG 2024", 1150, 750, 1, 1)
    
    // Set group properties
    lm.SetGroupOpacity("UI", 0.8)
    
    // Flatten and save
    result := lm.Flatten()
    result.SavePNG("starry-night-composition.png")
    
    // Save individual layers for editing
    lm.ExportPSD("starry-night-project.psd")
}

func drawMountains(dc *advancegg.Context) {
    // Draw mountain silhouettes
    dc.MoveTo(0, 600)
    dc.LineTo(200, 400)
    dc.LineTo(400, 500)
    dc.LineTo(600, 350)
    dc.LineTo(800, 450)
    dc.LineTo(1000, 300)
    dc.LineTo(1200, 400)
    dc.LineTo(1200, 800)
    dc.LineTo(0, 800)
    dc.ClosePath()
    dc.Fill()
}

func drawStars(dc *advancegg.Context, count int) {
    dc.SetRGB(1, 1, 1)
    for i := 0; i < count; i++ {
        x := rand.Float64() * 1200
        y := rand.Float64() * 400
        size := 1 + rand.Float64()*2
        dc.DrawCircle(x, y, size)
        dc.Fill()
    }
}