This repository has been archived on 2023-08-08. You can view files and clone it, but cannot push or open issues or pull requests.
tomo-old/artist/chisel.go

117 lines
3.0 KiB
Go
Raw Normal View History

2023-01-09 06:03:19 +00:00
package artist
import "image"
import "image/color"
import "git.tebibyte.media/sashakoshka/tomo"
// ShadingProfile contains shading information that can be used to draw chiseled
// objects.
type ShadingProfile struct {
Highlight Pattern
Shadow Pattern
Stroke Pattern
Fill Pattern
2023-01-09 06:03:19 +00:00
StrokeWeight int
ShadingWeight int
}
// Engraved reverses the shadown and highlight colors of the ShadingProfile to
// produce a new ShadingProfile with an engraved appearance.
func (profile ShadingProfile) Engraved () (reversed ShadingProfile) {
reversed = profile
reversed.Highlight = profile.Shadow
reversed.Shadow = profile.Highlight
return
}
// ChiseledRectangle draws a rectangle with a chiseled/embossed appearance,
// according to the ShadingProfile passed to it.
func ChiseledRectangle (
destination tomo.Canvas,
profile ShadingProfile,
bounds image.Rectangle,
) (
updatedRegion image.Rectangle,
) {
// FIXME: this breaks when the bounds are smaller than the border or
// shading weight
stroke := profile.Stroke
highlight := profile.Highlight
shadow := profile.Shadow
fill := profile.Fill
strokeWeight := profile.StrokeWeight
shadingWeight := profile.ShadingWeight
data, stride := destination.Buffer()
2023-01-09 06:03:19 +00:00
bounds = bounds.Canon()
updatedRegion = bounds
strokeWeightVector := image.Point { strokeWeight, strokeWeight }
shadingWeightVector := image.Point { shadingWeight, shadingWeight }
shadingBounds := bounds
shadingBounds.Min = shadingBounds.Min.Add(strokeWeightVector)
shadingBounds.Max = shadingBounds.Max.Sub(strokeWeightVector)
shadingBounds = shadingBounds.Canon()
fillBounds := shadingBounds
fillBounds.Min = fillBounds.Min.Add(shadingWeightVector)
fillBounds.Max = fillBounds.Max.Sub(shadingWeightVector)
fillBounds = fillBounds.Canon()
width := float64(bounds.Dx())
height := float64(bounds.Dy())
yy := 0
for y := bounds.Min.Y; y < bounds.Max.Y; y ++ {
xx := 0
for x := bounds.Min.X; x < bounds.Max.X; x ++ {
var pixel color.RGBA
point := image.Point { x, y }
switch {
case point.In(fillBounds):
pixel = fill.AtWhen (
xx - strokeWeight - shadingWeight,
yy - strokeWeight - shadingWeight,
fillBounds.Dx(), fillBounds.Dy())
2023-01-09 06:03:19 +00:00
case point.In(shadingBounds):
var highlighted bool
// FIXME: this doesn't work quite right, the
// slope of the line is somewhat off.
bottomCorner :=
float64(xx) < float64(yy) *
(width / height)
if bottomCorner {
highlighted =
float64(xx) <
height - float64(yy)
} else {
highlighted =
width - float64(xx) >
float64(yy)
}
shadingSource := shadow
2023-01-09 06:03:19 +00:00
if highlighted {
shadingSource = highlight
2023-01-09 06:03:19 +00:00
}
pixel = shadingSource.AtWhen (
xx - strokeWeight,
yy - strokeWeight,
shadingBounds.Dx(),
shadingBounds.Dy())
2023-01-09 06:03:19 +00:00
default:
pixel = stroke.AtWhen (
xx, yy, bounds.Dx(), bounds.Dy())
2023-01-09 06:03:19 +00:00
}
data[x + y * stride] = pixel
2023-01-09 06:03:19 +00:00
xx ++
}
yy ++
}
return
}