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() }
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 makeDot(v mgl32.Vec2, a float32, i int, clr mgl32.Vec4) mesh.Mesh { m := mesh.Mesh{ Nmbr: mesh.Number(i), Dpth: 0.5, Vrts: []mgl32.Vec2{ {-dotx, 0}, // 0 {0, -doty}, // 1 {dotx, 0}, // 2 {0, doty}, // 3 }, Clrs: []mgl32.Vec4{ clr, }, Trngls: []mesh.Triangle{ { Vnd: mesh.Nd{0, 1, 2}, Flvr: mesh.CONVEX, }, { Vnd: mesh.Nd{2, 3, 0}, Flvr: mesh.CONVEX, }, }, } m.Transform(mgl32.HomogRotate2D(a)) // rotate by a m.Transform(mgl32.Translate2D(v.Elem())) // translate by v return m }
/** 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 (ai *AI) moveAlongPath(targetPosition mgl32.Vec2, path []graph.Node) { minDistance2 := square(float32(ai.Me.Size) + costMapReduction*1.3) var pathNode *mapNode var pathVecs []mgl32.Vec2 for _, rawNode := range path { node := rawNode.(*mapNode) pos := mgl32.Vec2{float32(node.X) * costMapReduction, float32(node.Y) * costMapReduction} if pathNode == nil && dist2(ai.Me.Position, pos) >= minDistance2 { pathNode = node } pathVecs = append(pathVecs, pos) } if pathNode == nil { ai.addStatusMessage("Failed to find path node that was far enough away. Moving directly to objective.") ai.Path = []mgl32.Vec2{ai.Me.Position, targetPosition} ai.g.SetTargetPos(targetPosition.X(), targetPosition.Y()) return } ai.Path = pathVecs ai.g.SetTargetPos(float32(pathNode.X*costMapReduction), float32(pathNode.Y*costMapReduction)) }
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 (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 (c *Camera) project(pt mgl32.Vec2) mgl32.Vec2 { var ( screen = pt.Vec4(1, 1) out mgl32.Vec4 ) out = c.Projection.Mul4x1(screen) return out.Vec2() }
func (c *Camera) unproject(pt mgl32.Vec2) mgl32.Vec2 { var ( screen = pt.Vec4(1, 1) out mgl32.Vec4 ) out = c.Inverse.Mul4x1(screen) out = out.Mul(1.0 / out[3]) return out.Vec2() }
func normalize(v1 mgl32.Vec2, length float32) mgl32.Vec2 { length_current := v1.Len() if length_current > 0 { v1 = v1.Mul(length / length_current) } return v1 }
func (te *TextElement) updateImage(size mgl32.Vec2) { // Initialize the context. bg := image.Transparent c := te.getContext() text := te.GetHiddenText() if len(text) == 0 { text = te.props.placeholder r, g, b, _ := te.props.textColor.RGBA() placeholderColor := color.RGBA{uint8(r), uint8(g), uint8(b), 80} c.SetSrc(image.NewUniform(placeholderColor)) } // Establish image dimensions and do word wrap textHeight := c.PointToFixed(float64(te.props.textSize)) var width int var height int = int(textHeight >> 6) words := strings.Split(text, " ") lines := []string{""} lineNb := 0 for _, word := range words { wordWithSpace := fmt.Sprintf("%v ", word) dimensions, _ := c.StringDimensions(wordWithSpace) width += int(dimensions.X >> 6) if width > int(size.X()) { width = int(dimensions.X >> 6) height += int(dimensions.Y>>6) + 1 lines = append(lines, "") lineNb += 1 } lines[lineNb] = fmt.Sprintf("%v%v", lines[lineNb], wordWithSpace) } if te.props.height > 0 { height = int(te.props.height) } rgba := image.NewRGBA(image.Rect(0, 0, int(size.X()), height+int(textHeight>>6)/3)) draw.Draw(rgba, rgba.Bounds(), bg, image.ZP, draw.Src) c.SetClip(rgba.Bounds()) c.SetDst(rgba) // Draw the text. pt := freetype.Pt(0, int(textHeight>>6)) for _, line := range lines { _, err := c.DrawString(line, pt) if err != nil { log.Printf("Error drawing string: %v\n", err) return } pt.Y += textHeight } te.img.SetImage(imaging.FlipV(rgba)) te.img.SetWidth(float32(rgba.Bounds().Size().X)) te.img.SetHeight(float32(rgba.Bounds().Size().Y)) }
func (c *Camera) ScreenToWorldCoords(screenCoords mgl32.Vec2) mgl32.Vec2 { // http://stackoverflow.com/questions/7692988/ var ( half = c.ScreenSize.Mul(0.5) pt = mgl32.Vec2{ (screenCoords.X() - half.X()) / half.X(), (half.Y() - screenCoords.Y()) / half.Y(), } ) return c.unproject(pt) }
func (r *SplashRenderer) splashConfig(sheet *twodee.Spritesheet, pt mgl32.Vec2, name string) twodee.SpriteConfig { frame := sheet.GetFrame(name) return twodee.SpriteConfig{ View: twodee.ModelViewConfig{ pt.X() + frame.Width/2.0, pt.Y() + frame.Height/2.0, 0.0, // Center 0, 0, 0, 1.0, 1.0, 1.0, }, Frame: frame.Frame, } }
func (h *HudLayer) highlightSpriteConfig(sheet *twodee.Spritesheet, pt mgl32.Vec2, name string) twodee.SpriteConfig { frame := sheet.GetFrame(name) return twodee.SpriteConfig{ View: twodee.ModelViewConfig{ pt.X() + frame.Width/2.0, pt.Y() + frame.Height/6.0, 0.0, // Left aligned 0, 0, 0, 1.0, 1.0, 1.0, }, Frame: frame.Frame, } }
func computeMiter(lineA, lineB mgl32.Vec2, halfThick float32) (miter mgl32.Vec2, length float32) { var ( tangent mgl32.Vec2 tmp mgl32.Vec2 ) tangent = lineA.Add(lineB).Normalize() miter = mgl32.Vec2{-tangent[1], tangent[0]} tmp = mgl32.Vec2{-lineA[1], lineA[0]} length = halfThick / miter.Dot(tmp) return }
func (h *HudLayer) cursorSpriteConfig(sheet *twodee.Spritesheet, pt mgl32.Vec2, cursor string) twodee.SpriteConfig { frame := sheet.GetFrame(cursor) return twodee.SpriteConfig{ View: twodee.ModelViewConfig{ pt.X(), pt.Y(), 0.0, 0, 0, 0, 1.0, 1.0, 1.0, }, Frame: frame.Frame, } }
func (s *Sprite) textureBounds(textureBounds mgl32.Vec2) render.UniformSprite { return render.NewUniformSprite( s.bounds.X()/textureBounds.X(), s.bounds.Y()/textureBounds.Y(), s.offset.X()/textureBounds.X(), 1.0-(s.offset.Y()+s.bounds.Y()-1.0)/textureBounds.Y(), ) }
func (te *TextElement) Render(size, offset mgl32.Vec2) mgl32.Vec2 { te.props.size, te.props.offset = size, offset textWidth, textHeight := size.X(), size.Y() if te.props.width > 0 { textWidth = te.props.width } if te.props.height > 0 { textHeight = te.props.height } if te.previousProps != te.props { te.updateImage(mgl32.Vec2{textWidth, textHeight}) te.previousProps = te.props } return te.img.Render(size, offset) }
// 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 (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 }
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 (ai *AI) getPseudoMe() *agario.Cell { firstCell := ai.OwnCells[0] me := &agario.Cell{ ID: firstCell.ID, Name: firstCell.Name, Heading: firstCell.Heading, Color: firstCell.Color, IsVirus: firstCell.IsVirus, } var avgPosition mgl32.Vec2 for _, cell := range ai.OwnCells { me.Size += cell.Size if avgPosition.X() == 0 && avgPosition.Y() == 0 { avgPosition = cell.Position continue } avgPosition = avgPosition.Add(cell.Position) } n := float32(len(ai.OwnCells)) avgPosition[0] = avgPosition[0] / n avgPosition[1] = avgPosition[1] / n me.Position = avgPosition return me }
/** 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 createTextVertices(text string, position mgl32.Vec2, size float32, font *Font) (vertices []mgl32.Vec2, uvs []mgl32.Vec2) { x := position.X() y := float32(currentWindow.Height()) - position.Y() for c, char := range text { i := float32(c) upLeft := mgl32.Vec2{x + i*size, y + size} upRight := mgl32.Vec2{x + i*size + size, y + size} downRight := mgl32.Vec2{x + i*size + size, y} downLeft := mgl32.Vec2{x + i*size, y} vertices = append(vertices, upLeft, downLeft, upRight) vertices = append(vertices, downRight, upRight, downLeft) glyph := font.font.Glyphs().Find(string(char)) fullWidth := float32(font.font.Width) fullHeight := float32(font.font.Height) width := float32(glyph.Width) height := float32(glyph.Height) x := float32(glyph.X) y := float32(glyph.Y) uvX := x / fullWidth uvY := (fullHeight - y) / fullHeight uvWidth := width / fullWidth uvHeight := height / fullHeight uvUpLeft := mgl32.Vec2{uvX, uvY} uvUpRight := mgl32.Vec2{uvX + uvWidth, uvY} uvDownRight := mgl32.Vec2{uvX + uvWidth, uvY - uvHeight} uvDownLeft := mgl32.Vec2{uvX, uvY - uvHeight} uvs = append(uvs, uvUpLeft, uvDownLeft, uvUpRight) uvs = append(uvs, uvDownRight, uvUpRight, uvDownLeft) } return }
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 (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 (ai *AI) movePathed(position mgl32.Vec2) { minDistance2 := square(float32(ai.Me.Size) + costMapReduction*1.3) if dist2(ai.Me.Position, position) < minDistance2 { ai.addStatusMessage("Objective is within minimum distance. Moving directly to objective.") ai.Path = []mgl32.Vec2{ai.Me.Position, position} ai.g.SetTargetPos(position.X(), position.Y()) return } // meNode := ai.Map.GetNode(gameToCostMap(ai.Me.Position.Elem())) // positionNode := ai.Map.GetNode(gameToCostMap(position.Elem())) // path, cost, nodes := search.AStar(meNode, positionNode, ai.Map, nil, nil) // if path == nil { // ai.addStatusMessage("Failed to find path. Trying undirected.") // ai.movePathedUndirected(position) // return // } // ai.addStatusMessage(fmt.Sprintf("A*: path cost: %.2f / nodes expanded: %d", cost, nodes)) positionNode := ai.Map.GetNode(gameToCostMap(position.Elem())) path, cost := ai.DijkstraMap.To(positionNode) if path == nil { ai.addStatusMessage("movePathed: Failed to find path. Moving directly to objective.") ai.Path = []mgl32.Vec2{ai.Me.Position, position} ai.g.SetTargetPos(position.X(), position.Y()) return } ai.addStatusMessage(fmt.Sprintf("movePathed: path cost: %.2f", cost)) ai.moveAlongPath(position, path) }
func (ie *ImageElement) Render(size, offset mgl32.Vec2) mgl32.Vec2 { ie.size, ie.offset = size, offset width, height := ie.getWidth(size.X()), ie.getHeight(size.X()) if ie.img != nil { if width <= 0 && height <= 0 { width = float32(ie.img.Bounds().Size().X) height = float32(ie.img.Bounds().Size().Y) } else if width <= 0 { width = height * float32(ie.img.Bounds().Size().X) / float32(ie.img.Bounds().Size().Y) } else if height <= 0 { height = width * float32(ie.img.Bounds().Size().Y) / float32(ie.img.Bounds().Size().X) } } imgSize := mgl32.Vec2{width, height} ie.node.SetScale(imgSize.Vec3(0)) ie.node.SetTranslation(offset.Vec3(0)) ie.offset = offset ie.Hitbox.SetSize(imgSize) return imgSize }
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) }
func makeTriangle(n mesh.Number, d float32, o mgl32.Vec2) mesh.Mesh { return mesh.Mesh{ Nmbr: n, Dpth: d, Vrts: []mgl32.Vec2{ o.Add(mgl32.Vec2{0, 0}), o.Add(mgl32.Vec2{0, 100}), o.Add(mgl32.Vec2{100, 100}), }, Clrs: []mgl32.Vec4{ {0.7, 1.0, 0.0, 0.7}, }, Trngls: []mesh.Triangle{ {Vnd: mesh.Nd{0, 1, 2}}, }, } }