package graphics import ( "fmt" "math/rand" "image/color" rl "github.com/gen2brain/raylib-go/raylib" ) type Graphics struct { Style Style Bounds Rect } type Style struct { StrokeColor, FillColor color.RGBA StrokeWeight float32 Stroke, Fill bool } func (g *Graphics) GetGraphicsWidth() int32 { return int32(g.Bounds.Width) } func (g *Graphics) GetGraphicsHeight() int32 { return int32(g.Bounds.Height) } func (g *Graphics) PushStyle() { } func (g *Graphics) PopStyle() { } func (g *Graphics) SetStrokeColor(c Color) { g.Style.StrokeColor = color.RGBA { R: c.R, G: c.G, B: c.B, A: c.A } } func (g *Graphics) SetFillColor(c Color) { g.Style.FillColor = color.RGBA { R: c.R, G: c.G, B: c.B, A: c.A } } func (g *Graphics) SetStrokeWeight(w float32) { g.Style.StrokeWeight = w } func (g *Graphics) SetStroke(b bool) { g.Style.Stroke = b } func (g *Graphics) SetFill(b bool) { g.Style.Fill = b } func (g *Graphics) PushMatrix() { rl.PushMatrix() } func (g *Graphics) Translate(p Point) { rl.Translatef(p.X, p.Y, 0) } func (g *Graphics) PopMatrix() { rl.PopMatrix() } func (g *Graphics) BeginClip(r Rect) { rlRect := r.ToRL() rint := (&rlRect).ToInt32() rl.BeginScissorMode(rint.X, rint.Y, rint.Width, rint.Height) } func (g *Graphics) EndClip() { rl.EndScissorMode() } func (g *Graphics) BeginAdditiveBlend() { rl.BeginBlendMode(rl.BlendAdditive) } func (g *Graphics) EndBlend() { rl.EndBlendMode() } func (g *Graphics) BeginTexture(t rl.RenderTexture2D) { rl.BeginTextureMode(t) } func (g *Graphics) EndTexture() { rl.EndTextureMode() } func (g *Graphics) DrawRect(r Rect) { if g.Style.Fill { rl.DrawRectangleRec(r.ToRL(), g.Style.FillColor) } if g.Style.Stroke { saveLineWidth := rl.GetLineWidth() rl.SetLineWidth(g.Style.StrokeWeight) rl.DrawRectangleLines( int32(r.X), int32(r.Y), int32(r.Width), int32(r.Height), g.Style.StrokeColor, ) rl.SetLineWidth(saveLineWidth) } } func (g *Graphics) DrawLine(a, b Point) { saveLineWidth := rl.GetLineWidth() rl.SetLineWidth(g.Style.StrokeWeight) rl.DrawLineV(a.ToRL(), b.ToRL(), g.Style.StrokeColor) rl.SetLineWidth(saveLineWidth) } type Color color.RGBA func RGBA(r, g, b, a uint8) Color { return Color { R: r, G: g, B: b, A: a } } type HSBA struct { H uint S, B float32 A uint8 } type Point rl.Vector3 type Vec rl.Vector3 type Rect rl.Rectangle func (p *Point) Add(v Vec) Point { return Point { X: p.X + v.X, Y: p.Y + v.Y, Z: p.Z + v.Z } } func (p Point) ToRL() rl.Vector2 { return rl.Vector2 { X: p.X, Y: p.Y } } func (p Point) ToRL3() rl.Vector3 { return rl.Vector3 { X: p.X, Y: p.Y, Z: p.Z } } /** * scale the given rect down to the target rect * maintaining the aspect ratio of the original rect */ func (r Rect) UL() Point { return Point { X: r.X, Y: r.Y } } func (r Rect) ToRL() rl.Rectangle { return rl.Rectangle { X: r.X, Y: r.Y, Width: r.Width, Height: r.Height } } func (r Rect) ScaleTo(tgt Rect) Rect { outputWidth := tgt.Width outputHeight := tgt.Height aspect := r.Width / r.Height tgtAspect := outputWidth / outputHeight if aspect < tgtAspect { // source is relatively taller than the target // so we set the output height to the target height // and calculate the width based on source aspect and center outputWidth = float32(outputHeight) * aspect } else { // source is relatively wider than the target // so we set the output width to the target width // and calculate the height based on source aspect and center outputHeight = float32(outputWidth) / aspect } // output width and height are correct -- center within TargetBounds x := tgt.X + tgt.Width / 2.0 - outputWidth / 2.0 y := tgt.Y + tgt.Height / 2.0 - outputHeight / 2.0 return Rect { X: x, Y: y, Width: outputWidth, Height: outputHeight, } } var ( FlourescentHues = []float32{ 0, // hot magenta-red 30, // neon orange 60, // acid yellow 120, // laser green 180, // cyan 210, // electric blue 270, // ultraviolet purple } FlourescentColors = makeFlourescentColors() ) func Clamp(c rl.Color, min uint8, max uint8) rl.Color { return rl.NewColor( uint8(rl.Clamp(float32(c.R), float32(min), float32(max))), uint8(rl.Clamp(float32(c.G), float32(min), float32(max))), uint8(rl.Clamp(float32(c.B), float32(min), float32(max))), uint8(rl.Clamp(float32(c.A), float32(min), float32(max))), ) } func makeFlourescentColors() []rl.Color { fc := make([]rl.Color, len(FlourescentHues)) for i, hue := range(FlourescentHues) { fc[i] = rl.ColorFromHSV(hue, 1.0, 1.0) } fmt.Printf("flourescent colors --> %v\n", fc) return fc } type ColorCycle interface { Next() rl.Color } type ArrayBackedColorCycle struct { colors []rl.Color index int } func NewFixedColorCycle(colors []rl.Color) *ArrayBackedColorCycle { return &ArrayBackedColorCycle { colors: colors, index: 0, } } func (c ArrayBackedColorCycle) Shuffle(seed int64) *ArrayBackedColorCycle { r := rand.New(rand.NewSource(seed)) cprime := &ArrayBackedColorCycle { colors: make([]rl.Color, len(c.colors)), index: 0, } copy(cprime.colors, c.colors) r.Shuffle(len(c.colors), func(i, j int) { cprime.colors[i], cprime.colors[j] = cprime.colors[j], cprime.colors[i] }) fmt.Printf("shuffled colors --> %v\n", cprime.colors) return cprime } func (c *ArrayBackedColorCycle) Next() rl.Color { color := c.colors[c.index] c.index = (c.index + 1) % len(c.colors) return color }