After seeing geekmaster's "eink algorithmic art" demos, I fancied and dusted off a 30 years old demo -- see the included original Byte Magazine extract! (with a bonus p486 rescan to fix original download URL

)
Teaser code for illustrative purpose only,
Spoiler:
PHP Code:
#!/bin/sh
#=============================
# 3D - Projects a 3D object to a 2D screen
# Inspired by "eink algorithmic art" thread at https://www.mobileread.com/forums/showthread.php?t=172182
# usage: 3D
# Only tested on Kindle3 (firmware 3.3, Busybox 1.7.2 Almquist Shell)
#------------------------------
# Copyright (c) 2012 PoP under MIT License:
# Copyright (c) 2012 geekmaster under MIT License:
# http://www.opensource.org/licenses/mit-license.php
#------------------------------
# Revision History:
# v4.0 2012-04-05 PoP ported to Kindle3
# v3.0 1986-12-20 PoP ported to IBM PC
# v2.0 1983-09-14 PoP ported to C=64
# v1.0 1982-11-11 PoP ported to Apple][
# v0.0 1981-01-01 A. Pickholtz see pp 474-505 BYTE magazine: http://malus.exotica.org.uk/~buzz/byte/pdf/BYTE%20Vol%2007-11%201982-11%20Graphics.pdf
#------------------------------
# Global vars:
# B bank -PI..PI scaled
# CB cos(bank)
# CH cos(heading)
# CM var C of 3d matrix scaled
# CP cos(pitch)
# BLOCK vectors of this object scaled
# D distance from camera scaled
# DF device frame buffer
# DK device keyboard
# DM var D of 3d matrix scaled
# DN device null
# DODECA vectors of this object scaled
# EM var E of 3d matrix scaled
# EDGE absolute value of EDGEi
# EDGEi OBJ current edge
# EDGE$i OBJ $i'th edge $i i-1..NE
# FP floating point scaling 10^4
# FH floating point rounding FP/2
# FM var F of 3d matrix scaled
# GM var G of 3d matrix scaled
# H heading -PI..PI scaled
# HX middle x screen pos 300
# HY middle y screen pos 400
# HM var H of 3d matrix scaled
# IM var I of 3d matrix scaled
# KQ bytes per pixel, 2 for Kindle3
# MX max x pos 0:599
# MY max y pos 0:799
# NE OBJ number of edges
# NV OBJ number of points
# OBJ current object scaled
# OCTA vectors of this object
# P pitch -PI..PI scaled
# P2 2*PI scaled
# PI PI scaled
# PN -PI scaled
# SB sin(bank)
# SH sin(heading)
# SP sin(pitch)
# TK device temporary key
# TETRA vectors of this object scaled
# U computing 2D projection scaled
# V computing 2D projection scaled
# VECTX$i OBJ $i'th X coord i=1..NV scaled
# VECTY$i OBJ $i'th Y coord i=1..NV scaled
# VECTZ$i OBJ $i'th Z coord i=1..NV scaled
# VX virtual x size, 300 for Kindle 3
# XX computing 2D projection scaled
# YY computing 2D projection scaled
# ZZ computing 2D projection scaled
# x1 temp coordinate scaled
# x2 temp coordinate scaled
# X3 computing 2D projection scaled
# y1 temp coordinate scaled
# y2 temp coordinate scaled
# Y3 computing 2D projection scaled
# Z3 computing 2D projection scaled
#-----------------------------
#=============================
# initvar - init global vars
#-----------------------------
initvar() {
DN=/dev/null DF=/dev/fb0 DK=/dev/input/event0 MX=599 MY=799 HX=300 HY=400
TK=/tmp/key; echo > $TK;
set $(eips -i|grep line_length); VX=$4
FP=10000 # fixed-point scale factor
FH=5000 # FP/2 (for rounding)
PI=31416 # PI (scaled)
P2=62832 # 2*PI (scaled)
PN=-31416 # -PI (scaled)
KQ=2 # K3 pixels per byte
P=0 B=0 H=0 D=135000
BLOCK="
8
52500 -20000 32500
-52500 -20000 32500
-52500 -20000 -32500
52500 -20000 -32500
52500 20000 32500
-52500 20000 32500
-52500 20000 -32500
52500 20000 -32500
17
-1 2 3 4 1 5 6 7 8 5
-2 6 3 7 2
-4 8"
DODECA="
20
0 -21408 56052
34644 -34644 34644
56052 0 21408
34644 34644 34644
0 21408 56052
-34644 34644 34644
-56052 0 21408
-34644 -34644 34644
-21408 -56052 0
21408 -56052 0
21408 56052 0
-21408 56052 0
-34644 -34644 -34644
0 -21408 -56052
34644 -34644 -34644
56052 0 -21408
34644 34644 -34644
0 21408 -56052
-34644 34644 -34644
-56052 0 -21408
40
-1 2 3 4 5 6 7 8 1 5
-14 15 16 17 18 19 20 13 14 18
-8 9 10 2
-13 9
-15 10
-4 11 12 6
-17 11
-19 12
-16 3
-7 20"
OCTA="
6
0 75000 0
0 0 -25000
-25000 0 0
0 0 25000
25000 0 0
0 -75000 0
14
-1 2 6 4 1 3 6 5 1
-2 3 4 5 2"
TETRA="
4
-45000 -45000 -45000
45000 -45000 -45000
0 45000 0
0 45000 -45000
8
-1 2 3 1 4 2 3 4"
}
#===========================
# eupd - eink update display
#---------------------------
eupd() {
echo 1 >/proc/eink_fb/update_display # (for k3 and earlier)
# eips '' # (for k4 and newer)
}
#=============================
# line - Bresenham's line algorithm
# usage: line x0 y0 x y
#-----------------------------
line() {
local x0=$(($1/$KQ)) y0=$2 x=$(($3/$KQ)) y=$4; local dx dy sx sy e e2 xw xp=$x0
if [[ $x -gt $x0 ]];then dx=$((x-x0));sx=1; else dx=$((x0-x));sx=-1;fi
if [[ $y -gt $y0 ]];then dy=$((y0-y));sy=1; else dy=$((y-y0));sy=-1;fi
e=$((dx+dy)); echo -en "\xff${b#?}" | dd of=$DF bs=1 count=1 seek=$((y*VX+x)) 2>$DN
while [[ $x0 -ne $x -o $y0 -ne $y ]];do
xw=$((x0-xp)); [[ $xw -lt 0 ]]&& xw=$((-xw))
echo -en "\xff${b#?}" | dd of=$DF bs=1 count=1 seek=$((y0*VX+x0)) 2>$DN
e2=$((e+e))
if [[ $e2 -gt $dy ]];then e=$((e+dy));x0=$((x0+sx));fi
if [[ $e2 -lt $dx ]];then
xp=$x0;e=$((e+dx));y0=$((y0+sy))
fi
done;
}
#=============================
# sin - Taylor series sine function
# sin x ~= x - x^3/3! + x^5/5! - x^7/7!
# usage: sin x (-PI..PI)
# STDOUT: sin(x) (0..10K)
# O(5) @ +-90 deg, O(7) @ +-180 deg
# 10K fixed-point scale factor
#------------------------------
sin() {
local x=$1
while [[ $x -gt $PI ]];do x=$((x-$P2));done
while [[ $x -lt $PN ]];do x=$((x+$P2));done
local a=$x xs=$(((x*x+FH)/FP))
local xn=$(((x*xs+FH)/FP)) fn=6 # O(3)
a=$((a-(xn+fn/2)/fn)) xn=$(((xn*xs+FH)/FP)) fn=$((fn*20)) # O(5)
a=$((a+(xn+fn/2)/fn)) xn=$(((xn*xs+FH)/FP)) fn=$((fn*42)) # O(7)
a=$((a-(xn+fn/2)/fn)); echo $a
}
#=============================
# cos(x) = sin(pi/2-x) function
# usage: cos x (-PI..PI)
# STDOUT: cos(x) (0..10K)
# 10K fixed-point scale factor
#------------------------------
cos() {
sin $((PI/2+$(mult -10000 $1)))
}
#=============================
# mult - multiply scaled numbers
# usage: mult x y
# STDOUT: x * y (0..10K)
# 10K fixed-point scale factor
#------------------------------
mult() {
echo $((($1*$2+FH)/FP))
}
#=============================
# mat3d - compute projection matrix coefficients
# usage: mat3d
#-----------------------------
mat3d() {
CH=$(cos $H) SH=$(sin $H)
CP=$(cos $P) SP=$(sin $P)
CB=$(cos $B) SB=$(sin $B)
AM=$(( $(mult CB CH) - $(mult $(mult SH SP) SB))); # cos(B) cos(H) - sin(P) sin(B) sin(H)
BM=$((-$(mult CB SH) - $(mult $(mult SP CH) SB))); # - cos(B) sin(H) - sin(P) sin(B) cos(H)
CM=$(( $(mult CP SB))); # sin(B) cos(P)
DM=$(( $(mult CP SH))); # sin(H) cos(P)
EM=$(( $(mult CP CH))); # cos(P) cos(H)
FM=$SP; # sin(P)
GM=$((-$(mult SB CH) - $(mult $(mult SH SP) CB))); # - cos(H) sin(B) - sin(H) sin(P) cos(B)
HM=$(( $(mult SB SH) - $(mult $(mult CH SP) CB))); # sin(H) sin(B) - sin(P) cos(H) cos(B)
IM=$(( $(mult CP CB))); # cos(P) cos(B)
}
#==============================
# proj2d - project a vector
# usage: proj2d
#------------------------------
proj2d() {
XX=$((XX-XV))
YY=$((YY-YV))
ZZ=$((ZZ-ZV))
X3=$(($(mult AM XX)+$(mult BM YY)+$(mult CM ZZ)))
Y3=$(($(mult DM XX)+$(mult EM YY)+$(mult FM ZZ)))
Z3=$(($(mult GM XX)+$(mult HM YY)+$(mult IM ZZ)))
U=$((HX+ $(mult $(mult 300000 D)/Y3 X3))); # 30 horiz ppu adjustment
V=$((HY+ $(mult $(mult 300000 D)/Y3 Z3))); # 30 vert ppu adjustment
}
#=============================
# plot 3D object on 2D screen
# usage: plot object
#-----------------------------
plot() {
# read object vectors and edges:
NV=$1; shift; # number of points
for i in $(seq $NV); do
echo $((VECTX$i=$1)) $((VECTY$i=$2)) $((VECTZ$i=$3)) > $DN
shift; shift; shift
done
NE=$1; shift # number of edges
for i in $(seq $NE); do
echo $((EDGE$i=$1)) > $DN; shift
done
while :; do
# project object:
eips -c
eips 0 39 "P=$P H=$H B=$B D=$D"
mat3d
XV=$((-$(mult $(mult D CP) SH)))
YV=$((-$(mult $(mult D CP) CH)))
ZV=$((-$(mult D SP)))
for i in $(seq $NE); do
echo $((EDGEi=EDGE$i))>$DN
EDGE=$EDGEi
[[ $EDGE -le 0 ]]&& EDGE=$((-EDGE)) # ABS(EDGE)
echo $((XX=VECTX$EDGE))>$DN; echo $((YY=VECTY$EDGE))>$DN; echo $((ZZ=VECTZ$EDGE))>$DN
proj2d
if [[ $EDGEi -gt 0 ]]; then
x2=$U y2=$V
line $x1 $y1 $x2 $y2; eupd
fi
x1=$U y1=$V
done
if [[ -s $TK ]];then # get new Pitch, Heading, Bank, or Distance from keyboard input
set $(cat $TK); local k=$1; echo > $TK; waitforkey > $TK &
case $k in
25) P=$((P+P2/36));; # p +10dg
35) H=$((H+P2/36));; # h +10dg
48) B=$((B+P2/36));; # b +10dg
44) D=$((D-2*FP));; # z zoom in
22) D=$((D+2*FP));; # u zoom out
19) P=0 H=0 B=0 D=135000;; # r home
102) return;; # HOME quit program
esac
fi
done
}
#=============================
# main program entry point
#-----------------------------
lipc-set-prop com.lab126.powerd preventScreenSaver 1
killall -stop cvm # pause framework
initvar # init global vars
while :; do
eips -c
eips 15 4 " _/_/_/ 3D"
eips 15 5 " _/ 4.0 _/_/_/"
eips 15 6 " _/_/ by _/ _/"
eips 15 7 " _/ PoP _/ _/"
eips 15 8 "_/_/_/ _/ _/"
eips 15 9 " _/_/_/"
eips 15 15 "Select object to plot:"
eips 15 16 "Q - BLOCK"
eips 15 17 "W - OCTAHEDRON"
eips 15 18 "E - TETRAHEDRON"
eips 15 19 "R - DODECAHEDRON"
eips 15 20 "Home - Quit"
eips 15 28 "While object is being plot:"
eips 15 29 "R reset view"
eips 15 30 "P + pitch"
eips 15 31 "H + heading"
eips 15 32 "B + bank"
eips 15 33 "Z zoom"
eips 15 34 "U un zoom"
eips 15 35 "Home - Select new object"
waitforkey > $TK; set $(cat $TK); local k=$1; echo > $TK;
case $k in
16) plot $BLOCK;;
17) plot $OCTA;;
18) plot $TETRA;;
19) plot $DODECA;;
102) killall -cont cvm; lipc-set-prop com.lab126.powerd preventScreenSaver 0; exit;;
esac
done
extract the attached zip to preserve tabs, escaped characters, etc.
In particular, note the
echo $((VECTX$i=$1))>$DN construct to dynamically define and assign VECTOR$i variables in absence of shell arrays

.
I have included definitions for a couple of objects. It should be somewhat easy to modify and define vectors for more.
Use the keyboard to interactively control viewing angles and distance. When in trouble, press Home key twice to exit.
WARNINGS:
Well, this script is certainly not fast, and only meant for as a fun demo in /bin/sh education. It will only work on the K3, when started from an ssh session or from a launchpad shortcut. I have not thoroughly tested it (I am a bit surprised that it even works at all given the /bin/sh quirks I encountered). A "C formula'42" implementation would be a relief.
It will fail displaying correctly when zooming too close. Proper clipping is not implemented.
And Oh, sorry for too much white space... I felt it was cryptic enough without "optimizing" further.