package main import ( "fmt" "image" "image/color" "image/draw" "math" "time" "git.niplace.ru/XoxJlopeZi4BB/dev/fb" "github.com/golang/freetype" "github.com/golang/freetype/truetype" "golang.org/x/image/font" "golang.org/x/image/font/gofont/gomono" ) var Width, Height = fb.Resolution() const ( cubeSize = 50 Zoom = 1000.0 FOV = 350 frameCount = 120 rotationStep = math.Pi / 60 ) type Point3D struct { X, Y, Z float64 } type Point2D struct { X, Y int } func rotateX(p Point3D, angle float64) Point3D { cosA := math.Cos(angle) sinA := math.Sin(angle) return Point3D{ X: p.X, Y: p.Y*cosA - p.Z*sinA, Z: p.Y*sinA + p.Z*cosA, } } func rotateY(p Point3D, angle float64) Point3D { cosA := math.Cos(angle) sinA := math.Sin(angle) return Point3D{ X: p.X*cosA + p.Z*sinA, Y: p.Y, Z: -p.X*sinA + p.Z*cosA, } } func project(p Point3D) Point2D { scale := Zoom / (p.Z + FOV) return Point2D{ X: int(p.X*scale + float64(Width)/2), Y: int(p.Y*scale + float64(Height)/2), } } func drawLine(img *image.Paletted, p1, p2 Point2D, col color.Color) { dx := abs(p2.X - p1.X) dy := abs(p2.Y - p1.Y) sx := -1 if p1.X < p2.X { sx = 1 } sy := -1 if p1.Y < p2.Y { sy = 1 } err := dx - dy for { img.Set(p1.X, p1.Y, col) if p1.X == p2.X && p1.Y == p2.Y { break } e2 := 2 * err if e2 > -dy { err -= dy p1.X += sx } if e2 < dx { err += dx p1.Y += sy } } } func abs(x int) int { if x < 0 { return -x } return x } /* func Map[S, T any](v S, f func(T) T) S { } */ func main() { // Define the vertices of the cube vertices := []Point3D{ {-cubeSize, -cubeSize, -cubeSize}, {cubeSize, -cubeSize, -cubeSize}, {cubeSize, cubeSize, -cubeSize}, {-cubeSize, cubeSize, -cubeSize}, {-cubeSize, -cubeSize, cubeSize}, {cubeSize, -cubeSize, cubeSize}, {cubeSize, cubeSize, cubeSize}, {-cubeSize, cubeSize, cubeSize}, } // Define the edges of the cube edges := [][2]int{ {0, 1}, {1, 2}, {2, 3}, {3, 0}, {4, 5}, {5, 6}, {6, 7}, {7, 4}, {0, 4}, {1, 5}, {2, 6}, {3, 7}, } // Palette for the GIF palette := []color.Color{color.Black, color.White} var ( fontSize = 96.0 DPI = 72.0 spacing = 1.5 ) f, err := truetype.Parse(gomono.TTF) if err != nil { panic(err) } ctx := freetype.NewContext() ctx.SetDPI(DPI) ctx.SetFont(f) ctx.SetFontSize(fontSize) ctx.SetClip(image.Rect(0, 0, Width, Height)) ctx.SetSrc(image.NewUniform(palette[1])) ctx.SetHinting(font.HintingNone) var text string = "text" var fps int // Generate frames for i := 0; i < frameCount; i++ { angle := float64(i) * rotationStep img := image.NewPaletted(image.Rect(0, 0, Width, Height), palette) draw.Draw(img, img.Bounds(), &image.Uniform{color.Black}, image.Point{}, draw.Src) ctx.SetDst(img) // Rotate and project vertices projVertices := make([]Point2D, len(vertices)) for j, v := range vertices { rotated := rotateY(rotateX(v, angle), angle) projVertices[j] = project(rotated) } // Draw edges for _, edge := range edges { p1 := projVertices[edge[0]] p2 := projVertices[edge[1]] drawLine(img, p1, p2, color.White) } text = fmt.Sprint(fps) pt := freetype.Pt(30, 30+int(ctx.PointToFixed(fontSize)>>6)) _, err = ctx.DrawString(text, pt) if err != nil { panic(err) } pt.Y += ctx.PointToFixed(fontSize * spacing) t := time.Now() err := fb.Draw(img) if err != nil { panic(err) } d := time.Since(t) fps = int(time.Second / d) } }