func tween(a, b mgl32.Vec2) (x, y float32) { v := b.Sub(a) v = v.Mul(0.5) v = a.Add(v) return v.Elem() }
/** Calculate line boundary points. * * Sketch: * * uh1___uh2 * .' '. * .' q '. * .' ' ' '. *.' ' .'. ' '. * ' .' ul'. ' * p .' '. r * * * ul can be found as above, uh1 and uh2 are much simpler: * * uh1 = q + ns * w/2, uh2 = q + nt * w/2 */ func (polyline *polyLine) renderBevelEdge(sleeve, current, next mgl32.Vec2) { t := next.Sub(current) len_t := t.Len() det := determinant(sleeve, t) if mgl32.Abs(det)/(sleeve.Len()*len_t) < LINES_PARALLEL_EPS && sleeve.Dot(t) > 0 { // lines parallel, compute as u1 = q + ns * w/2, u2 = q - ns * w/2 n := getNormal(t, polyline.halfwidth/len_t) polyline.normals = append(polyline.normals, n) polyline.normals = append(polyline.normals, n.Mul(-1)) polyline.generateEdges(current, 2) return // early out } // cramers rule sleeve_normal := getNormal(sleeve, polyline.halfwidth/sleeve.Len()) nt := getNormal(t, polyline.halfwidth/len_t) lambda := determinant(nt.Sub(sleeve_normal), t) / det d := sleeve_normal.Add(sleeve.Mul(lambda)) if det > 0 { // 'left' turn -> intersection on the top polyline.normals = append(polyline.normals, d) polyline.normals = append(polyline.normals, sleeve_normal.Mul(-1)) polyline.normals = append(polyline.normals, d) polyline.normals = append(polyline.normals, nt.Mul(-1)) } else { polyline.normals = append(polyline.normals, sleeve_normal) polyline.normals = append(polyline.normals, d.Mul(-1)) polyline.normals = append(polyline.normals, nt) polyline.normals = append(polyline.normals, d.Mul(-1)) } polyline.generateEdges(current, 4) }
func (c *Container) mouseClick(button int, release bool, position mgl32.Vec2) { offsetPos := position.Sub(c.offset) c.Hitbox.MouseClick(button, release, offsetPos.Sub(c.backgroundOffset)) for _, child := range c.children { child.mouseClick(button, release, offsetPos.Sub(c.elementsOffset)) } }
func (c *Container) mouseMove(position mgl32.Vec2) { offsetPos := position.Sub(c.offset) c.Hitbox.MouseMove(offsetPos.Sub(c.backgroundOffset)) for _, child := range c.children { child.mouseMove(offsetPos.Sub(c.elementsOffset)) } }
func SegmentCircleIntersect(radius float32, center, start, finish mgl32.Vec2) (mgl32.Vec2, error) { d := finish.Sub(start) f := start.Sub(center) a := d.Dot(d) b := f.Mul(2).Dot(d) c := f.Dot(f) - radius*radius discriminant := b*b - 4*a*c if discriminant < 0 { return mgl32.Vec2{}, fmt.Errorf("No intersection") } else { discriminant = float32(math.Sqrt(float64(discriminant))) t1 := (-b - discriminant) / (2 * a) t2 := (-b + discriminant) / (2 * a) if t1 >= 0 && t1 <= 1 { return mgl32.Vec2{start.X() + t1*d.X(), start.Y() + t1*d.Y()}, nil } if t2 >= 0 && t2 <= 1 { return mgl32.Vec2{start.X() + t2*d.X(), start.Y() + t2*d.Y()}, nil } } return mgl32.Vec2{}, fmt.Errorf("No intersections") }
func (polyline *polyLine) render(coords []float32) { var sleeve, current, next mgl32.Vec2 polyline.vertices = []mgl32.Vec2{} polyline.normals = []mgl32.Vec2{} coords_count := len(coords) is_looping := (coords[0] == coords[coords_count-2]) && (coords[1] == coords[coords_count-1]) if !is_looping { // virtual starting point at second point mirrored on first point sleeve = mgl32.Vec2{coords[2] - coords[0], coords[3] - coords[1]} } else { // virtual starting point at last vertex sleeve = mgl32.Vec2{coords[0] - coords[coords_count-4], coords[1] - coords[coords_count-3]} } for i := 0; i+3 < coords_count; i += 2 { current = mgl32.Vec2{coords[i], coords[i+1]} next = mgl32.Vec2{coords[i+2], coords[i+3]} polyline.renderEdge(sleeve, current, next) sleeve = next.Sub(current) } if is_looping { polyline.renderEdge(sleeve, next, mgl32.Vec2{coords[2], coords[3]}) } else { polyline.renderEdge(sleeve, next, next.Add(sleeve)) } if polyline.join == LINE_JOIN_NONE { polyline.vertices = polyline.vertices[2 : len(polyline.vertices)-2] } polyline.draw(is_looping) }
func (polyline *polyLine) renderNoEdge(sleeve, current, next mgl32.Vec2) { sleeve_normal := getNormal(sleeve, polyline.halfwidth/sleeve.Len()) polyline.normals = append(polyline.normals, sleeve_normal) polyline.normals = append(polyline.normals, sleeve_normal.Mul(-1)) sleeve = next.Sub(current) sleeve_normal = getNormal(sleeve, polyline.halfwidth/sleeve.Len()) polyline.normals = append(polyline.normals, sleeve_normal.Mul(-1)) polyline.normals = append(polyline.normals, sleeve_normal) polyline.generateEdges(current, 4) }
// TwoSegmentIntersect - find the intersection point of two line segments <p11-p12> and <p21-p22> func TwoSegmentIntersect(p11, p12, p21, p22 mgl32.Vec2) (mgl32.Vec2, error) { p := p11 q := p21 r := p12.Sub(p11) s := p22.Sub(p21) if math.Abs(float64(Vec2Cross(r, s))) < 0.0000001 { return mgl32.Vec2{}, fmt.Errorf("No intersections: lines parallel") } t := Vec2Cross(q.Sub(p), s) / Vec2Cross(r, s) u := Vec2Cross(p.Sub(q), r) / Vec2Cross(s, r) if t >= 0 && t <= 1 && u >= 0 && u <= 1 { return p.Add(r.Mul(t)), nil } return mgl32.Vec2{}, fmt.Errorf("No intersections") }
func ClickAndDragWindow(window *Window, hitbox Hitbox, c controller.Controller) { grabbed := false grabOffset := mgl32.Vec2{} hitbox.AddOnClick(func(button int, release bool, position mgl32.Vec2) { grabOffset = position grabbed = !release }) c.BindMouseAction(func() { grabbed = false }, controller.MouseButton1, controller.Release) c.BindAxisAction(func(xpos, ypos float32) { if grabbed { position := mgl32.Vec2{xpos, ypos} window.SetTranslation(position.Sub(grabOffset).Vec3(0)) } }) }
func (c *Container) Render(size, offset mgl32.Vec2) mgl32.Vec2 { c.size, c.offset = size, offset padding := convertMargin(c.padding, c.paddingPercent, size.X()) margin := convertMargin(c.margin, c.marginPercent, size.X()) sizeMinusMargins := size.Sub(mgl32.Vec2{ margin.Left + margin.Right + padding.Left + padding.Right, margin.Top + margin.Bottom + padding.Top + padding.Bottom, }) containerSize := sizeMinusMargins if c.width > 0 { containerSize[0] = c.getWidth(size.X()) - padding.Left - padding.Right } if c.height > 0 { containerSize[1] = c.getHeight(size.X()) - padding.Top - padding.Bottom } var width, height, highest float32 = 0, 0, 0 for _, child := range c.children { childSize := child.Render(containerSize, mgl32.Vec2{width, height}) width += childSize.X() if width > containerSize.X() { height += highest highest = 0 childSize = child.Render(containerSize, mgl32.Vec2{0, height}) width = childSize.X() } if childSize.Y() > highest { highest = childSize.Y() } } height += highest if mgl32.FloatEqual(c.height, 0) { containerSize[1] = height } //offsets and sizes c.backgroundOffset = mgl32.Vec2{margin.Left, margin.Top} c.elementsOffset = mgl32.Vec2{margin.Left + padding.Left, margin.Top + padding.Top} backgroundSize := containerSize.Add(mgl32.Vec2{padding.Left + padding.Right, padding.Top + padding.Bottom}) totalSize := backgroundSize.Add(mgl32.Vec2{margin.Left + margin.Right, margin.Top + margin.Bottom}) c.background.SetScale(backgroundSize.Vec3(0)) c.background.SetTranslation(c.backgroundOffset.Vec3(0)) c.elementsNode.SetTranslation(c.elementsOffset.Vec3(0)) c.node.SetTranslation(c.offset.Vec3(0)) c.Hitbox.SetSize(backgroundSize) return totalSize }
/** Calculate line boundary points. * * Sketch: * * u1 * -------------+---...___ * | ```'''-- --- * p- - - - - - q- - . _ _ | w/2 * | ` ' ' r + * -------------+---...___ | w/2 * u2 ```'''-- --- * * u1 and u2 depend on four things: * - the half line width w/2 * - the previous line vertex p * - the current line vertex q * - the next line vertex r * * u1/u2 are the intersection points of the parallel lines to p-q and q-r, * i.e. the point where * * (q + w/2 * ns) + lambda * (q - p) = (q + w/2 * nt) + mu * (r - q) (u1) * (q - w/2 * ns) + lambda * (q - p) = (q - w/2 * nt) + mu * (r - q) (u2) * * with nt,nt being the normals on the segments s = p-q and t = q-r, * * ns = perp(s) / |s| * nt = perp(t) / |t|. * * Using the linear equation system (similar for u2) * * q + w/2 * ns + lambda * s - (q + w/2 * nt + mu * t) = 0 (u1) * <=> q-q + lambda * s - mu * t = (nt - ns) * w/2 * <=> lambda * s - mu * t = (nt - ns) * w/2 * * the intersection points can be efficiently calculated using Cramer's rule. */ func (polyline *polyLine) renderMiterEdge(sleeve, current, next mgl32.Vec2) { sleeve_normal := getNormal(sleeve, polyline.halfwidth/sleeve.Len()) t := next.Sub(current) len_t := t.Len() det := determinant(sleeve, t) // lines parallel, compute as u1 = q + ns * w/2, u2 = q - ns * w/2 if mgl32.Abs(det)/(sleeve.Len()*len_t) < LINES_PARALLEL_EPS && sleeve.Dot(t) > 0 { polyline.normals = append(polyline.normals, sleeve_normal) polyline.normals = append(polyline.normals, sleeve_normal.Mul(-1)) } else { // cramers rule nt := getNormal(t, polyline.halfwidth/len_t) lambda := determinant(nt.Sub(sleeve_normal), t) / det d := sleeve_normal.Add(sleeve.Mul(lambda)) polyline.normals = append(polyline.normals, d) polyline.normals = append(polyline.normals, d.Mul(-1)) } polyline.generateEdges(current, 2) }
func (m *Mob) moveTowardExit(elapsed time.Duration, level *Level) { var ( dest mgl32.Vec2 ok bool pct = float32(elapsed) / float32(time.Second) gridDist mgl32.Vec2 goalDist int32 stepDist = pct * m.Speed ) if dest, goalDist, ok = level.Grid.GetNextStepToSink(m.Pos); !ok { return } gridDist = dest.Sub(m.Pos) if goalDist == 1 && gridDist.Len() < stepDist+0.5 { m.PendingDisable = true } if gridDist.X() > 0 { m.swapState(Left, Right) } else { m.swapState(Right, Left) } m.Pos = m.Pos.Add(gridDist.Normalize().Mul(stepDist)) }
func moveC(v mgl32.Vec2) { d := v.Sub(lstPnt) // calculate delta vec lstPnt = v switch slctdC { case 0: c0dy += d[1] case 1: c1dy += d[1] case 2: c2dy += d[1] case 4: c4dx += d[0] case 5: c5dx += d[0] c5dy += d[1] } }
func (w *Window) mouseMove(position mgl32.Vec2) { w.mousePos = position.Sub(w.position) if w.element != nil { w.element.mouseMove(w.mousePos) } }
func (ie *ImageElement) mouseClick(button int, release bool, position mgl32.Vec2) { offsetPos := position.Sub(ie.offset) ie.Hitbox.MouseClick(button, release, offsetPos) }
func (ie *ImageElement) mouseMove(position mgl32.Vec2) { offsetPos := position.Sub(ie.offset) ie.Hitbox.MouseMove(offsetPos) }
func direction(a, b mgl32.Vec2) mgl32.Vec2 { return a.Sub(b).Normalize() }
func dist2(a, b mgl32.Vec2) float32 { diff := b.Sub(a) return square(diff.X()) + square(diff.Y()) }