94 lines
3.1 KiB
JavaScript
94 lines
3.1 KiB
JavaScript
import {eq_vect, eq_color, resolve_color, get_turtle_color, set_turtle_color, turtle_radius, turtle_angle, turn_to_rad, turtle_init, command_to_state, background_color, rotate, last} from "./turtle_geometry.js"
|
|
|
|
function states_to_call (prev, curr) {
|
|
const calls = []
|
|
// whose state should we use?
|
|
// pen states will only differ on more than one property
|
|
// if we use `loadstate`
|
|
// my sense is `prev`, but that may change
|
|
if (prev.pendown && !eq_vect(prev.position, curr.position)) {
|
|
calls.push(["line", prev.position[0], prev.position[1], curr.position[0], curr.position[1]])
|
|
}
|
|
if (!eq_color(curr.pencolor, prev.pencolor)) {
|
|
calls.push(["stroke", ...resolve_color(curr.pencolor)])
|
|
}
|
|
if (curr.penwidth !== prev.penwidth) {
|
|
calls.push(["strokeWeight", curr.penwidth])
|
|
}
|
|
return calls
|
|
}
|
|
|
|
function p5_call_root () {
|
|
return [
|
|
["background", ...resolve_color(background_color)],
|
|
["push"],
|
|
["rotate", Math.PI],
|
|
["scale", -1, 1],
|
|
["stroke", ...resolve_color(turtle_init.pencolor)],
|
|
]
|
|
}
|
|
|
|
function p5_render_turtle (state, calls) {
|
|
if (!state.visible) return
|
|
calls.push(["push"])
|
|
const [r, g, b, a] = get_turtle_color()
|
|
calls.push(["fill", r, g, b, a])
|
|
const {heading, pencolor, position: [x, y], pendown, penwidth} = state
|
|
const origin = [0, turtle_radius]
|
|
const [x1, y1] = origin
|
|
const [x2, y2] = rotate(origin, turtle_angle)
|
|
const [x3, y3] = rotate(origin, -turtle_angle)
|
|
calls.push(["translate", x, y])
|
|
// need negative turtle rotation with the other p5 translations
|
|
calls.push(["rotate", -turn_to_rad(heading)])
|
|
calls.push(["noStroke"])
|
|
calls.push(["beginShape"])
|
|
calls.push(["vertex", x1, y1])
|
|
calls.push(["vertex", x2, y2])
|
|
calls.push(["vertex", x3, y3])
|
|
calls.push(["endShape"])
|
|
calls.push(["strokeWeight", penwidth])
|
|
calls.push(["stroke", ...resolve_color(pencolor)])
|
|
if (pendown) calls.push(["line", 0, 0, x1, y1])
|
|
calls.push(["pop"])
|
|
return calls
|
|
}
|
|
|
|
export function p5 (commands) {
|
|
const all_states = {}
|
|
for (const command of commands) {
|
|
const [turtle_id, _, this_command] = command
|
|
let stack = all_states[turtle_id]
|
|
if (!stack) {
|
|
const new_stack = [turtle_init]
|
|
all_states[turtle_id] = new_stack
|
|
stack = new_stack
|
|
}
|
|
let prev_state = last(all_states[turtle_id])
|
|
const new_state = command_to_state(prev_state, this_command)
|
|
all_states[turtle_id].push(new_state)
|
|
}
|
|
console.log(all_states)
|
|
const [r, g, b, _] = resolve_color(background_color)
|
|
if ((r + g + b)/3 > 128) set_turtle_color([0, 0, 0, 150])
|
|
const p5_calls = [...p5_call_root()]
|
|
for (const states of Object.values(all_states)) {
|
|
p5_calls.push(["strokeWeight", 1])
|
|
p5_calls.push(["stroke", 255])
|
|
for (let i = 1; i < states.length; ++i) {
|
|
const prev = states[i - 1]
|
|
const curr = states[i]
|
|
const calls = states_to_call(prev, curr)
|
|
for (const call of calls) {
|
|
p5_calls.push(call)
|
|
}
|
|
}
|
|
p5_calls[0] = ["background", ...resolve_color(background_color)]
|
|
p5_render_turtle(states[states.length - 1], p5_calls)
|
|
}
|
|
p5_calls.push(["pop"])
|
|
return p5_calls
|
|
}
|
|
|
|
|