- Added tessellation module to handle path tessellation using Lyon. - Updated execution logic to record fill vertices and manage fill contours. - Integrated tessellation into command execution for lines, arcs, and filled shapes. - Enhanced TurtleState to track fill state and contours. - Modified TweenController to handle fill commands and update drawing commands accordingly. - Improved debug output for fill operations and tessellation processes.
11 KiB
Turtle Graphics Library
A modern turtle graphics library for Rust built on Macroquad with Lyon for high-quality GPU-accelerated rendering.
Project Status
✅ Stable - Complete Lyon integration with multi-contour fill system and live animation preview.
Features
- 🎨 Simple Builder API: Chain commands like
forward(100).right(90) - ⚡ Smooth Animations: Tweening support with easing functions and live fill preview
- 🚀 Instant Mode: Execute commands immediately without animation (speed ≥ 999)
- 🎯 High-Quality Rendering: Complete Lyon tessellation pipeline with GPU acceleration
- 🕳️ Multi-Contour Fills: Automatic hole detection with EvenOdd fill rule - draw cheese with holes!
- 📐 Self-Intersecting Paths: Stars, complex shapes - all handled correctly
- 🐢 Multiple Turtle Shapes: Triangle, classic turtle, circle, square, arrow, and custom shapes
- 💨 Lightweight: Fast compilation and runtime
Quick Start
use macroquad::prelude::*;
use turtle_lib_macroquad::*;
#[macroquad::main("Turtle")]
async fn main() {
// Create a turtle plan
let mut plan = create_turtle();
// Set speed (part of the plan)
plan.set_speed(100);
// Draw a square
for _ in 0..4 {
plan.forward(100).right(90);
}
// Create app (speed is managed by commands)
let mut app = TurtleApp::new().with_commands(plan.build());
loop {
clear_background(WHITE);
app.update();
app.render();
next_frame().await
}
}
API Overview
Creating Plans
let mut plan = create_turtle();
// Movement
plan.forward(100);
plan.backward(50);
// Rotation
plan.left(90); // degrees
plan.right(45);
// Circular arcs
plan.circle_left(50.0, 180.0, 36); // radius, angle (degrees), segments
plan.circle_right(50.0, 180.0, 36); // draws arc to the right
// Pen control
plan.pen_up();
plan.pen_down();
// Filling (with automatic hole detection)
plan.set_fill_color(BLUE);
plan.begin_fill();
// ... draw shape ...
plan.end_fill(); // Auto-closes and applies fill
// Appearance
plan.set_color(RED);
plan.set_pen_width(5.0);
plan.hide();
plan.show();
// Speed control (dynamic)
plan.set_speed(100); // Animated mode (< 999)
plan.set_speed(1000); // Instant mode (>= 999)
// Turtle shapes
plan.shape(ShapeType::Triangle);
plan.shape(ShapeType::Turtle); // Classic turtle shape
plan.shape(ShapeType::Circle);
plan.shape(ShapeType::Square);
plan.shape(ShapeType::Arrow);
// Custom shapes
let custom = TurtleShape::new(
vec![vec2(10.0, 0.0), vec2(-5.0, 5.0), vec2(-5.0, -5.0)],
true // filled
);
plan.set_shape(custom);
// Method chaining
plan.forward(100).right(90).forward(50);
Execution Modes
Speed is now controlled via commands, allowing dynamic switching during execution:
let mut plan = create_turtle();
// Fast initial positioning (instant mode)
plan.set_speed(1000);
plan.pen_up();
plan.goto(vec2(-100.0, -100.0));
// Slow animated drawing
plan.set_speed(50);
plan.pen_down();
plan.forward(200);
plan.right(90);
// Create app (no speed parameter needed)
let app = TurtleApp::new().with_commands(plan.build());
Speed Modes:
- Speed < 999: Animated mode with smooth tweening
- Speed >= 999: Instant mode (no animation)
- Default speed is 100.0 if not specified
Animation Loop
loop {
clear_background(WHITE);
app.update(); // Update animation state
app.render(); // Draw to screen
if app.is_complete() {
// All commands executed
}
next_frame().await
}
Examples
Run examples with:
# From turtle-lib-macroquad directory
cargo run --example square
cargo run --example koch
cargo run --example shapes
cargo run --example yinyang
cargo run --example stern
cargo run --example nikolaus
# Lyon proof-of-concept examples
cargo run --package turtle-lyon-poc --example yinyang --release
cargo run --package turtle-lyon-poc --example basic_shapes --release
cargo run --package turtle-lyon-poc --example fill_comparison --release
Available Examples
Basic Drawing
- square.rs: Basic square drawing
- koch.rs: Koch snowflake fractal
- shapes.rs: Demonstrates different turtle shapes
- stern.rs: Star pattern drawing
- nikolaus.rs: Nikolaus (Santa) drawing
Fill Examples
- yinyang.rs: Yin-yang symbol with automatic hole detection
- fill_demo.rs: Donut shape with hole
- fill_requirements.rs: Circle with red fill
- fill_advanced.rs: Complex shapes (star, swiss cheese, multiple holes)
- fill_circle_test.rs: Circle fills with different angles
- fill_instant_test.rs: Quick fill test in instant mode
Why Lyon?
- Automatic hole detection via EvenOdd fill rule
- GPU-accelerated rendering
- Standards-compliant (matches SVG, HTML Canvas)
- Handles any self-intersecting path
Basic Fill
let mut plan = create_turtle();
plan.set_fill_color(RED);
plan.begin_fill();
// Draw shape
for _ in 0..4 {
plan.forward(100);
plan.right(90);
}
plan.end_fill(); // Auto-closes and fills
Fill with Holes (Multi-Contour)
plan.set_fill_color(BLUE);
plan.begin_fill();
// Outer circle (first contour)
plan.circle_left(90.0, 360.0, 72);
// pen_up() closes current contour
plan.pen_up();
plan.goto(vec2(0.0, -30.0));
// pen_down() starts new contour
plan.pen_down();
// Inner circle (becomes a hole automatically with EvenOdd rule!)
plan.circle_left(30.0, 360.0, 36);
plan.end_fill(); // Auto-detects holes and fills correctly
Fill Features
- ✅ Live Preview - See fills progressively during animation
- ✅ Auto-Close - Automatically connects end point to start on
end_fill() - ✅ Multi-Contour -
pen_up()closes contour,pen_down()opens next one - ✅ Automatic Hole Detection - EvenOdd fill rule handles any complexity
- ✅ Self-Intersecting Paths - Stars and complex shapes work perfectly
Architecture
Module Structure
turtle-lib-macroquad/src/
├── lib.rs - Public API and TurtleApp
├── state.rs - TurtleState and TurtleWorld
├── commands.rs - TurtleCommand enum (consolidated commands)
├── builders.rs - Builder traits (DirectionalMovement, Turnable, etc.)
├── execution.rs - Command execution with fill support
├── tweening.rs - Animation/tweening controller with dynamic speed
├── drawing.rs - Rendering with Lyon tessellation
├── shapes.rs - Turtle shape definitions
├── tessellation.rs - Lyon tessellation utilities
├── circle_geometry.rs - Circle arc calculations
└── general/ - Type definitions (Angle, Length, etc.)
Design Principles
- State Management: Clean separation between turtle state and world state
- Command Queue: Commands queued and executed with optional tweening
- Consolidated Commands: Unified commands reduce duplication (Move, Turn, Circle)
- Dynamic Speed Control: Speed managed via SetSpeed commands for flexibility
- Tweening System: Smooth interpolation with easing functions
- Unified Lyon Rendering: All drawing operations use GPU-accelerated Lyon tessellation
- Lines, arcs, circles, fills - single high-quality rendering pipeline
- ~410 lines of code eliminated through architectural simplification
- Consistent quality across all primitives
Command Consolidation
The library uses consolidated commands to reduce code duplication:
- Move(distance): Replaces separate Forward/Backward (negative = backward)
- Turn(angle): Replaces separate Left/Right (negative = left, positive = right)
- Circle{direction, ...}: Unified circle command with CircleDirection enum
This design eliminates ~250 lines of duplicate code while maintaining the same user-facing API.
Workspace Structure
turtle/
├── turtle-lib-macroquad/ - Main library (Macroquad + Lyon)
├── turtle-lib/ - Legacy Bevy-based implementation
└── turtle-example/ - Legacy examples
The turtle-lib-macroquad package is the current and future focus of development.
Building and Running
# Check all packages
cargo check
# Run specific example
cargo run --package turtle-lib-macroquad --example yinyang
# Build release version
cargo build --release
# Run Lyon POC examples to see future rendering
cargo run --package turtle-lyon-poc --example yinyang --release
Development Status
✅ Completed
- Complete Lyon integration for all drawing primitives
- Multi-contour fill system with automatic hole detection
- Turtle movement and rotation (consolidated Move/Turn commands)
- Circle arcs (left/right with unified Circle command)
- Pen control (up/down) with contour management
- Color and pen width
- Multiple turtle shapes with custom shape support
- Tweening system with easing functions
- Dynamic speed control via SetSpeed commands
- Instant mode (speed ≥ 999) and animated mode (speed < 999)
- EvenOdd fill rule for complex self-intersecting paths
- Live fill preview during animation with progressive rendering
- Multi-contour support - pen_up/pen_down manage contours
- Command consolidation (~250 lines eliminated)
- Full Lyon migration (~410 total lines eliminated)
🎯 Future Possibilities
- Advanced stroke styling (caps, joins, dashing)
- Bezier curves and custom path primitives
- Additional examples and tutorials
What's New
Complete Lyon Migration ✨
All drawing operations now use GPU-accelerated Lyon tessellation:
- Unified pipeline: Lines, arcs, circles, and fills - all use the same high-quality rendering
- Simplified codebase: ~410 lines of code eliminated
- Better performance: GPU tessellation is faster than CPU-based primitives
- Consistent quality: No more mixed rendering approaches
Multi-Contour Fill System 🕳️
Advanced fill capabilities with automatic hole detection:
- EvenOdd fill rule: Draw shapes with holes - works like SVG and HTML Canvas
- Pen state management:
pen_up()closes contour,pen_down()opens next - Live preview: See fills progressively during animations
- Self-intersecting paths: Stars, complex shapes - all handled correctly
Architectural Improvements 🏗️
- Command consolidation: Unified Move/Turn/Circle commands (~250 lines eliminated)
- Dynamic speed control: Change speed during execution via commands
- Live animation preview: Progressive fill rendering during circle/arc drawing
License
MIT OR Apache-2.0
Contributing
Contributions are welcome! The library now has a stable foundation with complete Lyon integration and multi-contour fill support.