317 lines
6.4 KiB
Go
317 lines
6.4 KiB
Go
package graphics
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"image/color"
|
|
rl "github.com/gen2brain/raylib-go/raylib"
|
|
)
|
|
|
|
type Graphics struct {
|
|
Style Style
|
|
Bounds Rect
|
|
}
|
|
|
|
func CreateGraphics(bounds Rect) *Graphics {
|
|
return &Graphics {
|
|
Bounds: bounds,
|
|
Style: Style {
|
|
Fill: false,
|
|
FillColor: rl.RayWhite,
|
|
Stroke: true,
|
|
StrokeColor: rl.Black,
|
|
StrokeWeight: 1.0,
|
|
},
|
|
}
|
|
}
|
|
|
|
type Style struct {
|
|
StrokeColor, FillColor color.RGBA
|
|
StrokeWeight float32
|
|
Stroke, Fill bool
|
|
}
|
|
|
|
func (g *Graphics) Center() Point {
|
|
return g.Bounds.Center()
|
|
}
|
|
|
|
func (g *Graphics) Begin() {
|
|
rl.BeginBlendMode(rl.BlendAlphaPremultiply)
|
|
g.PushMatrix()
|
|
g.Translate(g.Bounds.UL())
|
|
g.BeginClip(g.Bounds)
|
|
}
|
|
|
|
func (g *Graphics) Clear() {
|
|
rl.ClearBackground(rl.Blank)
|
|
}
|
|
|
|
func (g *Graphics) Background(c color.RGBA) {
|
|
rl.ClearBackground(c)
|
|
}
|
|
|
|
func (g *Graphics) End() {
|
|
g.EndBlend()
|
|
g.EndClip()
|
|
g.PopMatrix()
|
|
}
|
|
|
|
func (g *Graphics) Width() float32 {
|
|
return g.Bounds.Width
|
|
}
|
|
|
|
func (g *Graphics) Height() float32 {
|
|
return g.Bounds.Height
|
|
}
|
|
|
|
func (g *Graphics) WidthInt32() int32 {
|
|
return int32(g.Bounds.Width)
|
|
}
|
|
|
|
func (g *Graphics) HeightInt32() int32 {
|
|
return int32(g.Bounds.Height)
|
|
}
|
|
|
|
|
|
func (g *Graphics) PushStyle() {
|
|
}
|
|
|
|
func (g *Graphics) PopStyle() {
|
|
}
|
|
|
|
func (g *Graphics) SetStrokeColor(c color.RGBA) {
|
|
g.Style.StrokeColor = color.RGBA { R: c.R, G: c.G, B: c.B, A: c.A }
|
|
}
|
|
|
|
func (g *Graphics) SetFillColor(c color.RGBA) {
|
|
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) DrawTexture(t rl.Texture2D, p Point, c color.RGBA) {
|
|
rl.DrawTexture(t, int32(p.X), int32(p.Y), c)
|
|
}
|
|
|
|
|
|
func (g *Graphics) TransferTexture(t rl.Texture2D, src Rect, dst Rect, tint color.RGBA) {
|
|
rl.DrawTexturePro(t, src.ToRL(), dst.ToRL(), rl.Vector2{}, 0, tint)
|
|
}
|
|
|
|
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 HSBA struct {
|
|
H uint
|
|
S, B float32
|
|
A uint8
|
|
}
|
|
|
|
var Origin = Point { X: 0, Y: 0, Z: 0 }
|
|
|
|
type Point rl.Vector3
|
|
type Vec rl.Vector3
|
|
type Rect rl.Rectangle
|
|
|
|
func (r *Rect) Center() Point {
|
|
return Point {
|
|
X: r.X + r.Width / 2,
|
|
Y: r.X + r.Height / 2,
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|