Files
sumi/internal/graphics/graphics.go

258 lines
5.3 KiB
Go

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
}