Compare commits
2 Commits
78ecc84493
...
a3cad7d1bc
| Author | SHA1 | Date | |
|---|---|---|---|
| a3cad7d1bc | |||
| 8128c212ae |
112
README.md
112
README.md
@ -17,9 +17,32 @@ A modern turtle graphics library for Rust built on [Macroquad](https://macroquad
|
||||
- 🐢 **Multiple Turtle Shapes**: Triangle, classic turtle, circle, square, arrow, and custom shapes
|
||||
- 🔍 **Structured Logging**: Optional `tracing` integration for debugging (zero overhead when disabled)
|
||||
- 💨 **Lightweight**: Fast compilation and runtime
|
||||
- 📤 **SVG Export**: Export drawings to SVG format with viewBox and padding (feature-gated)
|
||||
|
||||
## Quick Start
|
||||
|
||||
The simplest example to draw a square:
|
||||
|
||||
```rust
|
||||
//! Minimal turtle example - just 10 lines!
|
||||
//!
|
||||
//! This is the simplest possible turtle program using the macro.
|
||||
|
||||
use turtle_lib::*;
|
||||
|
||||
#[turtle_main]
|
||||
fn hello() {
|
||||
turtle.set_pen_color(BLUE);
|
||||
for _ in 0..4 {
|
||||
turtle.forward(100.0);
|
||||
turtle.right(90.0);
|
||||
}
|
||||
}
|
||||
```
|
||||
The turtle starts at the center of the window, facing right (0 degrees). The above code draws a blue square.
|
||||
|
||||
The `turtle_main` macro sets up the Macroquad window, turtle initialization, and main loop for you. It expands to code similar to this:
|
||||
|
||||
```rust
|
||||
use macroquad::prelude::*;
|
||||
use turtle_lib::*;
|
||||
@ -108,7 +131,7 @@ plan.forward(100).right(90).forward(50);
|
||||
|
||||
### Execution Modes
|
||||
|
||||
Speed is now controlled via commands, allowing dynamic switching during execution:
|
||||
Speed controlled via commands, allowing dynamic switching during execution:
|
||||
|
||||
```rust
|
||||
let mut plan = create_turtle();
|
||||
@ -124,32 +147,15 @@ plan.pen_down();
|
||||
plan.forward(200);
|
||||
plan.right(90);
|
||||
|
||||
// Create app (no speed parameter needed)
|
||||
// Create app
|
||||
let app = TurtleApp::new().with_commands(plan.build());
|
||||
```
|
||||
|
||||
**Speed Modes:**
|
||||
- **Speed < 999**: Animated mode with smooth tweening
|
||||
- **Speed >= 999**: Instant mode (no animation)
|
||||
- **Speed >= 999**: Instant mode (no animation) the bigger the number the more segments will be added per frame.
|
||||
- Default speed is 100.0 if not specified
|
||||
|
||||
### Animation Loop
|
||||
|
||||
```rust
|
||||
loop {
|
||||
clear_background(WHITE);
|
||||
|
||||
app.update(); // Update animation state
|
||||
app.render(); // Draw to screen
|
||||
|
||||
if app.is_complete() {
|
||||
// All commands executed
|
||||
}
|
||||
|
||||
next_frame().await
|
||||
}
|
||||
```
|
||||
|
||||
## Debugging and Logging
|
||||
|
||||
The library uses [`tracing`](https://docs.rs/tracing) for structured diagnostic logging. This is completely optional - if you don't set up a subscriber, there's zero overhead.
|
||||
@ -177,6 +183,48 @@ RUST_LOG=turtle_lib=trace cargo run
|
||||
|
||||
**See the complete example**: [`examples/logging_example.rs`](turtle-lib/examples/logging_example.rs) demonstrates initialization, log levels, filtering, and example output.
|
||||
|
||||
## SVG Export
|
||||
|
||||
Export your turtle drawings to SVG format for use in web applications, vector graphics editors, or further processing.
|
||||
|
||||
### Enabling SVG Export
|
||||
|
||||
Add the `svg` feature to enable SVG export functionality:
|
||||
|
||||
```bash
|
||||
cargo run --example export_svg --features svg
|
||||
```
|
||||
|
||||
### Usage
|
||||
|
||||
```rust
|
||||
use turtle_lib::*;
|
||||
|
||||
// Create your drawing
|
||||
let mut plan = create_turtle();
|
||||
plan.forward(100).right(90).forward(100);
|
||||
|
||||
// Create app
|
||||
let mut app = TurtleApp::new().with_commands(plan.build());
|
||||
|
||||
// Export to SVG
|
||||
app.export_drawing("drawing.svg", export::DrawingFormat::Svg)?;
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
- **Complete Primitive Support**: Lines, circles, arcs, polygons, and fills
|
||||
- **Automatic viewBox**: Includes 20px padding around the entire drawing
|
||||
- **Color and Styling**: Preserves colors, pen width, and fill colors
|
||||
- **Multi-Contour Fills**: Exports complex fills with holes using SVG paths
|
||||
- **Text Support**: Exports text elements with positioning
|
||||
|
||||
### Example
|
||||
|
||||
See [`examples/export_svg.rs`](turtle-lib/examples/export_svg.rs) for a complete example that draws various shapes and exports them to SVG.
|
||||
|
||||
The exported SVG can be opened in any web browser or vector graphics application.
|
||||
|
||||
## Examples
|
||||
|
||||
Run examples with:
|
||||
@ -188,6 +236,9 @@ cargo run --example yinyang
|
||||
cargo run --example stern
|
||||
cargo run --example nikolaus
|
||||
|
||||
# SVG export example (requires --features svg)
|
||||
cargo run --example export_svg --features svg
|
||||
|
||||
# Logging example - shows how to enable debug output
|
||||
cargo run --example logging_example
|
||||
RUST_LOG=turtle_lib=debug cargo run --example logging_example
|
||||
@ -210,15 +261,18 @@ RUST_LOG=turtle_lib=debug cargo run --example logging_example
|
||||
- **fill_circle_test.rs**: Circle fills with different angles
|
||||
- **fill_instant_test.rs**: Quick fill test in instant mode
|
||||
|
||||
#### Export
|
||||
- **export_svg.rs**: Demonstrates SVG export functionality (requires `--features svg`)
|
||||
|
||||
#### Debugging
|
||||
- **logging_example.rs**: Demonstrates how to enable and use tracing/logging output
|
||||
|
||||
## Why Lyon?
|
||||
|
||||
- Automatic hole detection via EvenOdd fill rule
|
||||
- Handles any self-intersecting path
|
||||
- GPU-accelerated rendering
|
||||
- Standards-compliant (matches SVG, HTML Canvas)
|
||||
- Handles any self-intersecting path
|
||||
|
||||
### Basic Fill
|
||||
```rust
|
||||
@ -283,15 +337,6 @@ turtle-lib/src/
|
||||
└── 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
|
||||
|
||||
## Workspace Structure
|
||||
|
||||
```
|
||||
@ -309,8 +354,14 @@ cargo check
|
||||
# Run specific example
|
||||
cargo run --example yinyang
|
||||
|
||||
# Run SVG export example (requires svg feature)
|
||||
cargo run --example export_svg --features svg
|
||||
|
||||
# Build release version
|
||||
cargo build --release
|
||||
|
||||
# Build with SVG support
|
||||
cargo build --features svg
|
||||
```
|
||||
|
||||
## Development Status
|
||||
@ -330,6 +381,7 @@ cargo build --release
|
||||
- **Live fill preview** during animation with progressive rendering
|
||||
- **Multi-contour support** - pen_up/pen_down manage contours
|
||||
- **Command consolidation**
|
||||
- **SVG Export** - Export drawings to SVG with viewBox and padding (feature-gated)
|
||||
|
||||
## What's New
|
||||
|
||||
|
||||
@ -3,111 +3,3 @@
|
||||
The main turtle graphics library built on Macroquad with Lyon tessellation.
|
||||
|
||||
**See the [main README](../README.md) for complete documentation.**
|
||||
|
||||
## Features
|
||||
|
||||
✅ **Complete Lyon Integration** - All drawing operations use GPU-optimized tessellation
|
||||
- Unified rendering pipeline for lines, arcs, circles, and fills
|
||||
- ~410 lines of code eliminated through architectural simplification
|
||||
- Consistent high-quality rendering across all primitives
|
||||
|
||||
✅ **Multi-Contour Fill System** - Advanced fill capabilities with automatic hole detection
|
||||
- EvenOdd fill rule for complex shapes with holes (like cheese or yin-yang symbols)
|
||||
- `pen_up()` closes current contour, `pen_down()` opens next contour
|
||||
- Progressive fill preview during animations
|
||||
- Support for self-intersecting paths
|
||||
|
||||
✅ **Smooth Animation** - Tweening system with live rendering
|
||||
- Configurable speed control
|
||||
- Frame-rate independent animation
|
||||
- Live fill preview during circle/arc drawing
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Using the `turtle_main` Macro (Recommended for Beginners)
|
||||
|
||||
The easiest way to create turtle programs is with the `turtle_main` macro:
|
||||
|
||||
```rust
|
||||
use macroquad::prelude::*;
|
||||
use turtle_lib::*;
|
||||
|
||||
#[turtle_main("My First Drawing")]
|
||||
fn my_drawing(turtle: &mut TurtlePlan) {
|
||||
turtle.set_pen_color(RED);
|
||||
turtle.forward(100.0);
|
||||
turtle.right(90.0);
|
||||
turtle.forward(100.0);
|
||||
}
|
||||
```
|
||||
|
||||
The macro automatically handles:
|
||||
- Window creation and setup
|
||||
- Turtle initialization
|
||||
- Rendering loop
|
||||
- Quit handling (ESC or Q keys)
|
||||
|
||||
### Manual Setup (For Advanced Use)
|
||||
|
||||
For more control over the application loop:
|
||||
|
||||
```rust
|
||||
use macroquad::prelude::*;
|
||||
use turtle_lib::*;
|
||||
|
||||
#[macroquad::main("Turtle")]
|
||||
async fn main() {
|
||||
let mut turtle = create_turtle();
|
||||
turtle.forward(100.0).right(90.0);
|
||||
|
||||
let mut app = TurtleApp::new().with_commands(turtle.build());
|
||||
|
||||
loop {
|
||||
clear_background(WHITE);
|
||||
app.update();
|
||||
app.render();
|
||||
next_frame().await;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Quick Examples
|
||||
|
||||
All examples now use the `turtle_main` macro for simplicity:
|
||||
|
||||
```bash
|
||||
# Run from this directory
|
||||
cargo run --example hello_turtle # Minimal 10-line example
|
||||
cargo run --example macro_demo # Simple square with macro
|
||||
cargo run --example square # Basic square drawing
|
||||
cargo run --example shapes # Different turtle shapes
|
||||
cargo run --example yinyang # Multi-contour fills with holes
|
||||
cargo run --example koch # Recursive fractals
|
||||
cargo run --example fill_demo # Fill with holes (donut)
|
||||
cargo run --example cheese_macro # Cheese example using macro
|
||||
cargo run --example fill_advanced # Complex shapes (manual setup)
|
||||
```
|
||||
|
||||
Most examples use `turtle_main` for simplicity. A few keep manual setup for custom UI or logging.
|
||||
|
||||
## Architecture Highlights
|
||||
|
||||
### Rendering Pipeline
|
||||
All drawing operations → Lyon tessellation → GPU mesh rendering
|
||||
|
||||
### DrawCommand Enum
|
||||
Simplified from 5 variants to 1:
|
||||
- `Mesh(MeshData)` - unified variant for all drawing operations
|
||||
|
||||
### Fill System
|
||||
- `FillState` tracks multiple contours (completed + current)
|
||||
- Pen state management automatically handles contour creation
|
||||
- EvenOdd tessellation provides automatic hole detection
|
||||
|
||||
See [LYON_COMPLETE.md](LYON_COMPLETE.md) and [MULTI_CONTOUR_FILLS.md](MULTI_CONTOUR_FILLS.md) for implementation details.
|
||||
|
||||
## Status
|
||||
|
||||
✅ **Stable** - Lyon integration complete, multi-contour fills working, all examples passing.
|
||||
|
||||
See [../README.md](../README.md) for full API documentation and project status.
|
||||
|
||||
@ -28,7 +28,7 @@ pub fn render_world(world: &TurtleWorld) {
|
||||
for turtle in &world.turtles {
|
||||
for cmd in &turtle.commands {
|
||||
match cmd {
|
||||
DrawCommand::Mesh { data, source } => {
|
||||
DrawCommand::Mesh { data, source: _ } => {
|
||||
// Rendering wie bisher
|
||||
draw_mesh(&data.to_mesh());
|
||||
// Hier könnte man das source für Debug/Export loggen
|
||||
@ -39,7 +39,7 @@ pub fn render_world(world: &TurtleWorld) {
|
||||
heading,
|
||||
font_size,
|
||||
color,
|
||||
source,
|
||||
source: _,
|
||||
} => {
|
||||
draw_text_command(text, *position, *heading, *font_size, *color);
|
||||
// Hier könnte man das source für Debug/Export loggen
|
||||
@ -80,7 +80,7 @@ pub fn render_world_with_tweens(world: &TurtleWorld, zoom_level: f32) {
|
||||
for turtle in &world.turtles {
|
||||
for cmd in &turtle.commands {
|
||||
match cmd {
|
||||
DrawCommand::Mesh { data, source } => {
|
||||
DrawCommand::Mesh { data, source: _ } => {
|
||||
draw_mesh(&data.to_mesh());
|
||||
}
|
||||
DrawCommand::Text {
|
||||
@ -89,7 +89,7 @@ pub fn render_world_with_tweens(world: &TurtleWorld, zoom_level: f32) {
|
||||
heading,
|
||||
font_size,
|
||||
color,
|
||||
source,
|
||||
source: _,
|
||||
} => {
|
||||
draw_text_command(text, *position, *heading, *font_size, *color);
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ pub mod svg_export {
|
||||
use crate::commands::TurtleCommand;
|
||||
use crate::export::{DrawingExporter, ExportError};
|
||||
use crate::state::{DrawCommand, TurtleWorld};
|
||||
use macroquad::prelude::Vec2;
|
||||
use std::fs::File;
|
||||
use svg::{
|
||||
node::element::{Circle, Line, Polygon, Text as SvgText},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user