Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions geometry.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,11 @@ func (u Vec) Project(v Vec) Vec {
return v.Unit().Scaled(len)
}

// AngleTo returns angle between u and v.
func (u Vec) AngleTo(v Vec) float64 {
return math.Cos(u.Unit().Dot(v.Unit()))
}

// Map applies the function f to both x and y components of the vector u and returns the modified
// vector.
//
Expand Down Expand Up @@ -1107,3 +1112,56 @@ func (m Matrix) Unproject(u Vec) Vec {
(-m[1]*(u.X-m[4]) + m[0]*(u.Y-m[5])) / det,
}
}

// Bezier is cubic Bézier curve used for interpolation. For more info
// see https://en.wikipedia.org/wiki/B%C3%A9zier_curve,
// In case you are looking for visualization see https://www.desmos.com/calculator/d1ofwre0fr
type Bezier struct {
Start, StartHandle, EndHandle, End Vec
redundant bool
}

// ZB is Zero Bezier Curve that skips calculation and always returns V(1, 0)
// Its mainly because Calculation uses lot of function calls and in case of
// particles, it can make some difference
var ZB = Constant(V(1, 0))

// B returns new curve. if curve is just placeholder use constant. Handles are
// relative to start and end point so:
//
// pixel.B(ZV, ZV, ZV, V(1, 0)) == Bezier{ZV, ZV, V(1, 0), V(1, 0)}
func B(start, startHandle, endHandle, end Vec) Bezier {
return Bezier{start, startHandle.Add(start), endHandle.Add(end), end, false}
}

// Linear returns linear Bezier curve
func Linear(start, end Vec) Bezier {
return B(start, ZV, ZV, end)
}

// Constant returns Bezier curve that always return same point,
// This is usefull as placeholder, because it skips calculation
func Constant(constant Vec) Bezier {
return Bezier{
Start: constant,
redundant: true,
}
}

// Point returns point along the curve determinate by t (0 - 1)
// You can of course pass any value though its really hard to
// predict what value will it return
func (b Bezier) Point(t float64) Vec {
if b.redundant || b.Start == b.End {
b.redundant = true
return b.Start
}

inv := 1.0 - t
c, d, e, f := inv*inv*inv, inv*inv*t*3.0, inv*t*t*3.0, t*t*t

return V(
b.Start.X*c+b.StartHandle.X*d+b.EndHandle.X*e+b.End.X*f,
b.Start.Y*c+b.StartHandle.Y*d+b.EndHandle.Y*e+b.End.Y*f,
)
}
51 changes: 51 additions & 0 deletions geometry_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1599,3 +1599,54 @@ func BenchmarkRect_IsIntersect(b *testing.B) {
// do a thing
}
}

type sub struct {
result pixel.Vec
t float64
}

func TestBezier(t *testing.T) {
tests := []struct {
curve pixel.Bezier

subTest []sub
name string
}{
{
pixel.Constant(pixel.V(1, 0)),
[]sub{
{pixel.V(1, 0), 0.0},
{pixel.V(1, 0), 100.0},
},
"constant",
},
{
pixel.Linear(pixel.V(1, 0), pixel.ZV),
[]sub{
{pixel.V(1, 0), 0.0},
{pixel.ZV, 1.0},
},
"lenear",
},
{
pixel.B(pixel.V(0, 1), pixel.V(1, 0), pixel.V(-1, 0), pixel.V(1, 0)),
[]sub{
{pixel.V(0, 1), 0.0},
{pixel.V(1, 0), 1.0},
{pixel.V(.5, .5), 0.5},
},
"curved",
},
}

for _, c := range tests {
t.Run(c.name, func(t *testing.T) {
for _, st := range c.subTest {
val := c.curve.Point(st.t)
if val != st.result {
t.Errorf("inputted: %v expected: %v got: %v", st.t, st.result, val)
}
}
})
}
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.12
require (
github.com/faiface/glhf v0.0.0-20181018222622-82a6317ac380
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7 // indirect
github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72
github.com/go-gl/mathgl v0.0.0-20190416160123-c4601bc793c7
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
Expand Down
14 changes: 7 additions & 7 deletions pixelgl/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (w *Window) SetMousePosition(v pixel.Vec) {
mainthread.Call(func() {
if (v.X >= 0 && v.X <= w.bounds.W()) &&
(v.Y >= 0 && v.Y <= w.bounds.H()) {
w.window.SetCursorPos(
w.Window.SetCursorPos(
v.X+w.bounds.Min.X,
(w.bounds.H()-v.Y)+w.bounds.Min.Y,
)
Expand Down Expand Up @@ -359,7 +359,7 @@ var buttonNames = map[Button]string{

func (w *Window) initInput() {
mainthread.Call(func() {
w.window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
w.Window.SetMouseButtonCallback(func(_ *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
switch action {
case glfw.Press:
w.tempInp.buttons[Button(button)] = true
Expand All @@ -368,7 +368,7 @@ func (w *Window) initInput() {
}
})

w.window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
w.Window.SetKeyCallback(func(_ *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
if key == glfw.KeyUnknown {
return
}
Expand All @@ -382,23 +382,23 @@ func (w *Window) initInput() {
}
})

w.window.SetCursorEnterCallback(func(_ *glfw.Window, entered bool) {
w.Window.SetCursorEnterCallback(func(_ *glfw.Window, entered bool) {
w.cursorInsideWindow = entered
})

w.window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
w.Window.SetCursorPosCallback(func(_ *glfw.Window, x, y float64) {
w.tempInp.mouse = pixel.V(
x+w.bounds.Min.X,
(w.bounds.H()-y)+w.bounds.Min.Y,
)
})

w.window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) {
w.Window.SetScrollCallback(func(_ *glfw.Window, xoff, yoff float64) {
w.tempInp.scroll.X += xoff
w.tempInp.scroll.Y += yoff
})

w.window.SetCharCallback(func(_ *glfw.Window, r rune) {
w.Window.SetCharCallback(func(_ *glfw.Window, r rune) {
w.tempInp.typed += string(r)
})
})
Expand Down
Loading