This is even more excellent.
This commit is contained in:
parent
d85fb2e638
commit
926008e491
4 changed files with 429 additions and 20 deletions
|
|
@ -23,7 +23,10 @@
|
|||
"Bash(/tmp/sim)",
|
||||
"Bash(cc -O2 -o /tmp/st2 /tmp/st2.c -lm)",
|
||||
"Bash(/tmp/st2)",
|
||||
"Bash(rm -f /tmp/st2 /tmp/st2.c)"
|
||||
"Bash(rm -f /tmp/st2 /tmp/st2.c)",
|
||||
"Bash(convert /tmp/vg_frame.ppm -crop 760x360+340+60 +repage /tmp/vg_faces.png)",
|
||||
"Bash(convert /tmp/vg_frame.ppm -crop 760x300+340+430 +repage /tmp/vg_googie.png)",
|
||||
"Bash(convert /tmp/vg_frame.ppm -crop 360x340+150+60 +repage /tmp/vg_angry.png)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
28
README.md
28
README.md
|
|
@ -3,7 +3,7 @@
|
|||
A starfield simulator — except instead of stars, colorful **vector-drawn
|
||||
platonic solids** tumble through space toward the camera.
|
||||
|
||||
**~110 shape types** are rendered as glowing wireframes — each spawns far away
|
||||
**~165 shape types** are rendered as glowing wireframes — each spawns far away
|
||||
at a random size, tumbles on its own random axis, and streams past the camera
|
||||
before being recycled at the render-distance sphere. Solids never overlap.
|
||||
|
||||
|
|
@ -20,15 +20,23 @@ The shape set includes:
|
|||
each lands on exactly the requested number of faces
|
||||
- **Star polygons:** {5/2}, {6/2}, {7/2}, {7/3}, {8/3}, {9/2}, {9/4}, {12/5},
|
||||
plus the **unicursal hexagram**
|
||||
- **Googie / atomic-age shapes**, most in both flat **2-D** and **3-D** forms:
|
||||
jet-age bowling-alley twinkles (4- and 8-point), a layered double starburst,
|
||||
an atomic burst with electron caps, a ray sunburst, boomerangs, kidney/amoeba
|
||||
blobs, orbital atoms, concentric orbit rings, and a dense ray-star — plus the
|
||||
naturally-3-D **Sputnik** satellite, a three-ring **gyroscope** cage, and a
|
||||
spike-orb sea-urchin
|
||||
- **Symbols & signs**, each in a flat **2-D** and an extruded **3-D** form:
|
||||
smiley face, biohazard, peace sign, cross, question mark, exclamation point,
|
||||
hash/pound (`#`), dollar sign (`$`), and pound sterling (`£`)
|
||||
- **Googie / atomic-age shapes** — a large set in the jet-age / space-age idiom:
|
||||
bowling-alley twinkles (4- and 8-point), a layered double starburst, atomic
|
||||
bursts with electron caps, ray sunbursts, boomerangs, kidney/amoeba blobs,
|
||||
concentric orbit rings, plus **30+ more truly-3-D objects**: radial
|
||||
**starbursts** and **sea-urchins** (6/8/12/20/32-spike, some ball-tipped),
|
||||
**gyroscope** orbit cages (2–6 rings), **orbital atoms** (2–6 orbits),
|
||||
ringed **Saturn** planets, ball-and-stick **molecules**, **diabolo**
|
||||
hourglasses, ray-stars, and a **Sputnik** satellite
|
||||
- **Symbols, signs & faces**, each in a flat **2-D** and an extruded **3-D**
|
||||
form: smiley, **frowny**, and **angry** faces, biohazard, peace sign, cross,
|
||||
question mark, exclamation point, hash/pound (`#`), dollar sign (`$`), pound
|
||||
sterling (`£`), and the **at sign (`@`)**
|
||||
- **Object iconography**, each in **2-D** and **3-D**: space invaders, UFOs,
|
||||
pac-man, alien heads, smoking pipes, umbrellas, and hands
|
||||
- **Live clocks** (analog and digital, 2-D and 3-D) that show the **actual
|
||||
current time** — their geometry is rebuilt every frame, so the analog hands
|
||||
sweep and the seven-segment digital display ticks along in real time
|
||||
- **Random 3-D asteroids:** lumpy convex-hull rocks generated fresh each run,
|
||||
with random vertex counts (≈7–26) giving each a different number of sides and
|
||||
level of complexity
|
||||
|
|
|
|||
BIN
vectorgons
BIN
vectorgons
Binary file not shown.
416
vectorgons.c
416
vectorgons.c
|
|
@ -6,13 +6,17 @@
|
|||
* Windowing & input via GLFW3, perspective via GLU.
|
||||
*
|
||||
* Features:
|
||||
* - 100+ shape types streaming at the camera: the 5 platonic solids,
|
||||
* - 160+ shape types streaming at the camera: the 5 platonic solids,
|
||||
* archimedeans, prisms, antiprisms, bipyramids, trapezohedra, the
|
||||
* many-faced solids (tri/tetra/.../hecato-hedron), star polygons and the
|
||||
* unicursal hexagram, googie / atomic-age starbursts, 2-D and 3-D symbols
|
||||
* (smiley, biohazard, peace, cross, ? ! # $ £), 4/5/6-D polytopes
|
||||
* (tesseract, penteract, 24-cell, ...) that morph as they tumble, plus
|
||||
* randomly generated 3-D convex-hull asteroids
|
||||
* unicursal hexagram, a big set of googie / atomic-age 3-D objects
|
||||
* (starbursts, sea-urchins, gyroscopes, orbital atoms, ringed planets,
|
||||
* molecules, diabolos, sputniks), 2-D and 3-D symbols (smiley, frowny,
|
||||
* angry, biohazard, peace, cross, ? ! # $ £ @), object iconography
|
||||
* (space invaders, UFOs, pac-man, alien heads, pipes, umbrellas, hands)
|
||||
* and live analog/digital clocks showing the real current time, 4/5/6-D
|
||||
* polytopes (tesseract, penteract, 24-cell, ...) that morph as they
|
||||
* tumble, plus randomly generated 3-D convex-hull asteroids
|
||||
* - WASD pans the camera and the arrow keys rotate it
|
||||
* - User-settable render distance (how far away solids spawn)
|
||||
* - Random per-body sizes (user-settable min / max)
|
||||
|
|
@ -57,7 +61,7 @@
|
|||
#define MAXD 6
|
||||
#define MAX_VERTS 128
|
||||
#define MAX_EDGES 512
|
||||
#define MAX_SHAPES 160
|
||||
#define MAX_SHAPES 220
|
||||
#define TAU 6.283185307179586
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -70,6 +74,7 @@ typedef struct {
|
|||
|
||||
static Solid solids[MAX_SHAPES];
|
||||
static int num_shapes = 0;
|
||||
static int clock_idx[4] = {-1,-1,-1,-1}; /* analog2d, analog3d, digital2d, digital3d */
|
||||
|
||||
static float frand(void); /* uniform [0,1); defined below */
|
||||
|
||||
|
|
@ -347,9 +352,11 @@ static void sym_poly(SymB *b, const double *xy, int n, int closed) {
|
|||
}
|
||||
static double sym_deg(double d) { return d * TAU / 360.0; }
|
||||
|
||||
/* Turn the accumulated strokes into a Solid: flat if depth<=0, else extruded. */
|
||||
static void sym_finish(SymB *b, float depth) {
|
||||
Solid *s = new_solid(3);
|
||||
/* Fill an existing Solid from the strokes: flat if depth<=0, else extruded.
|
||||
* (Used both for one-shot shapes and for the live clocks, which rewrite their
|
||||
* solid in place every frame.) */
|
||||
static void sym_fill_solid(Solid *s, SymB *b, float depth) {
|
||||
s->dim = 3; s->nv = 0; s->ne = 0;
|
||||
if (depth <= 0.0f) {
|
||||
for (int k = 0; k < b->np; k++) PV(s, b->px[k], b->py[k], 0, 0,0,0);
|
||||
for (int k = 0; k < b->ne; k++) AE(s, b->ea[k], b->eb[k]);
|
||||
|
|
@ -365,6 +372,7 @@ static void sym_finish(SymB *b, float depth) {
|
|||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
static void sym_finish(SymB *b, float depth) { sym_fill_solid(new_solid(3), b, depth); }
|
||||
|
||||
/* ---- individual symbol strokes (drawn roughly within [-1,1]) ------- */
|
||||
|
||||
|
|
@ -636,6 +644,342 @@ static void gen_spikeorb3d(void) {
|
|||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* ================================================================== */
|
||||
/* More googie / atomic-age 3-D objects, plus faces and the '@' sign. */
|
||||
/* ================================================================== */
|
||||
|
||||
/* Symmetric unit-direction sets for radial bursts. Returns the count.
|
||||
* 0:octahedron(6) 1:cube(8) 2:icosahedron(12) 3:dodecahedron(20)
|
||||
* 4:icosa+dodeca(32). */
|
||||
static int dir_set(int which, double out[][3]) {
|
||||
const double P = 1.6180339887, Q = 0.6180339887;
|
||||
double t[40][3]; int n = 0;
|
||||
if (which == 0) {
|
||||
double d[6][3] = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
|
||||
for (int i=0;i<6;i++){ t[n][0]=d[i][0];t[n][1]=d[i][1];t[n][2]=d[i][2];n++; }
|
||||
} else if (which == 1) {
|
||||
for (int x=-1;x<=1;x+=2) for (int y=-1;y<=1;y+=2) for (int z=-1;z<=1;z+=2)
|
||||
{ t[n][0]=x;t[n][1]=y;t[n][2]=z;n++; }
|
||||
} else {
|
||||
if (which == 2 || which == 4) {
|
||||
double d[12][3]={{0,1,P},{0,1,-P},{0,-1,P},{0,-1,-P},{1,P,0},{1,-P,0},
|
||||
{-1,P,0},{-1,-P,0},{P,0,1},{P,0,-1},{-P,0,1},{-P,0,-1}};
|
||||
for (int i=0;i<12;i++){ t[n][0]=d[i][0];t[n][1]=d[i][1];t[n][2]=d[i][2];n++; }
|
||||
}
|
||||
if (which == 3 || which == 4) {
|
||||
for (int x=-1;x<=1;x+=2) for (int y=-1;y<=1;y+=2) for (int z=-1;z<=1;z+=2)
|
||||
{ t[n][0]=x;t[n][1]=y;t[n][2]=z;n++; }
|
||||
double e[12][3]={{0,Q,P},{0,Q,-P},{0,-Q,P},{0,-Q,-P},{Q,P,0},{Q,-P,0},
|
||||
{-Q,P,0},{-Q,-P,0},{P,0,Q},{P,0,-Q},{-P,0,Q},{-P,0,-Q}};
|
||||
for (int i=0;i<12;i++){ t[n][0]=e[i][0];t[n][1]=e[i][1];t[n][2]=e[i][2];n++; }
|
||||
}
|
||||
}
|
||||
for (int i=0;i<n;i++){
|
||||
double L=sqrt(t[i][0]*t[i][0]+t[i][1]*t[i][1]+t[i][2]*t[i][2]); if(L<1e-9)L=1;
|
||||
out[i][0]=t[i][0]/L; out[i][1]=t[i][1]/L; out[i][2]=t[i][2]/L;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
/* small ring "ball" of `seg` points at p, in the plane perpendicular to u */
|
||||
static void add_ball(Solid *s, double px,double py,double pz,
|
||||
double ux,double uy,double uz, double rad, int seg) {
|
||||
double rx=uy, ry=-ux, rz=0, rl=sqrt(rx*rx+ry*ry+rz*rz);
|
||||
if (rl<1e-6){ rx=1;ry=0;rz=0;rl=1; }
|
||||
rx/=rl; ry/=rl; rz/=rl;
|
||||
double sx=uy*rz-uz*ry, sy=uz*rx-ux*rz, sz=ux*ry-uy*rx;
|
||||
int first=-1, prev=-1;
|
||||
for (int k=0;k<seg;k++){
|
||||
double a=TAU*k/seg; int idx=s->nv;
|
||||
PV(s, px+rad*(cos(a)*rx+sin(a)*sx), py+rad*(cos(a)*ry+sin(a)*sy),
|
||||
pz+rad*(cos(a)*rz+sin(a)*sz), 0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx;
|
||||
}
|
||||
if(first>=0&&prev>=0) AE(s,prev,first);
|
||||
}
|
||||
|
||||
/* radial spike burst (starburst): a spoke to each direction, optionally
|
||||
* alternating long/short, optionally capped with a little ball */
|
||||
static void gen_burst3d(int which, double longr, double shortr, int balls) {
|
||||
Solid *s=new_solid(3);
|
||||
double d[40][3]; int nd=dir_set(which,d);
|
||||
int c=s->nv; PV(s,0,0,0,0,0,0);
|
||||
for (int i=0;i<nd;i++){
|
||||
double r=(shortr>0 && (i&1))?shortr:longr;
|
||||
double tx=d[i][0]*r, ty=d[i][1]*r, tz=d[i][2]*r;
|
||||
int tip=s->nv; PV(s,tx,ty,tz,0,0,0); AE(s,c,tip);
|
||||
if (balls) add_ball(s,tx,ty,tz,d[i][0],d[i][1],d[i][2],0.12,5);
|
||||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* great circles at spread orientations (gyroscope / orbit cage) */
|
||||
static void gen_rings3d(int nrings, int seg) {
|
||||
Solid *s=new_solid(3);
|
||||
for (int r=0;r<nrings;r++){
|
||||
double ax=TAU*r/(2.0*nrings), ay=TAU*r/(3.0*nrings)+0.3*r;
|
||||
int first=-1, prev=-1;
|
||||
for (int i=0;i<seg;i++){
|
||||
double a=TAU*i/seg, x=cos(a), y=sin(a), z=0;
|
||||
double y1=y*cos(ax)-z*sin(ax), z1=y*sin(ax)+z*cos(ax); y=y1; z=z1;
|
||||
double x1=x*cos(ay)+z*sin(ay), z2=-x*sin(ay)+z*cos(ay); x=x1; z=z2;
|
||||
int idx=s->nv; PV(s,x,y,z,0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx;
|
||||
}
|
||||
AE(s,prev,first);
|
||||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* atomic orbital cluster: tilted elliptical orbits around an octahedral nucleus */
|
||||
static void gen_atomorbits(int norbits, int seg) {
|
||||
Solid *s=new_solid(3);
|
||||
for (int o=0;o<norbits;o++){
|
||||
double sp=TAU*o/norbits, tx=TAU*o/(norbits*2.0)+0.4;
|
||||
int first=-1, prev=-1;
|
||||
for (int i=0;i<seg;i++){
|
||||
double a=TAU*i/seg, x=cos(a), y=sin(a)*0.42, z=0;
|
||||
double x1=x*cos(sp)-y*sin(sp), y1=x*sin(sp)+y*cos(sp); x=x1; y=y1;
|
||||
double y2=y*cos(tx)-z*sin(tx), z2=y*sin(tx)+z*cos(tx); y=y2; z=z2;
|
||||
int idx=s->nv; PV(s,x,y,z,0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx;
|
||||
}
|
||||
AE(s,prev,first);
|
||||
}
|
||||
int b0=s->nv; double r=0.12;
|
||||
PV(s,r,0,0,0,0,0);PV(s,-r,0,0,0,0,0);PV(s,0,r,0,0,0,0);
|
||||
PV(s,0,-r,0,0,0,0);PV(s,0,0,r,0,0,0);PV(s,0,0,-r,0,0,0);
|
||||
int oe[12][2]={{0,2},{0,3},{0,4},{0,5},{1,2},{1,3},{1,4},{1,5},{2,4},{2,5},{3,4},{3,5}};
|
||||
for(int e=0;e<12;e++) AE(s,b0+oe[e][0],b0+oe[e][1]);
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* ringed planet (Saturn): a wireframe sphere with tilted equatorial ring(s) */
|
||||
static void gen_saturn3d(int nrings, double tilt) {
|
||||
Solid *s=new_solid(3);
|
||||
const double pi=TAU*0.5; int lats=3, seg=14;
|
||||
for (int la=1;la<=lats;la++){
|
||||
double phi=pi*la/(lats+1)-pi*0.5, y=sin(phi)*0.6, rr=cos(phi)*0.6;
|
||||
int first=-1, prev=-1;
|
||||
for (int i=0;i<seg;i++){ double a=TAU*i/seg; int idx=s->nv;
|
||||
PV(s,rr*cos(a),y,rr*sin(a),0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx; }
|
||||
AE(s,prev,first);
|
||||
}
|
||||
for (int m=0;m<2;m++){
|
||||
double mo=TAU*m/4; int first=-1, prev=-1;
|
||||
for (int i=0;i<seg;i++){ double a=TAU*i/seg, x=cos(a)*0.6, y=sin(a)*0.6, z=0;
|
||||
double x1=x*cos(mo)+z*sin(mo), z1=-x*sin(mo)+z*cos(mo);
|
||||
int idx=s->nv; PV(s,x1,y,z1,0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx; }
|
||||
AE(s,prev,first);
|
||||
}
|
||||
for (int rg=0;rg<nrings;rg++){
|
||||
double rad=1.0+rg*0.2; int first=-1, prev=-1, seg2=22;
|
||||
for (int i=0;i<seg2;i++){ double a=TAU*i/seg2, x=rad*cos(a), y=0, z=rad*sin(a);
|
||||
double y1=y*cos(tilt)-z*sin(tilt), z1=y*sin(tilt)+z*cos(tilt);
|
||||
int idx=s->nv; PV(s,x,y1,z1,0,0,0);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)AE(s,prev,idx);
|
||||
prev=idx; }
|
||||
AE(s,prev,first);
|
||||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* ball-and-stick molecule: a central ball bonded to balls in each direction */
|
||||
static void gen_molecule3d(int which) {
|
||||
Solid *s=new_solid(3);
|
||||
double d[40][3]; int nd=dir_set(which,d);
|
||||
int c=s->nv; PV(s,0,0,0,0,0,0);
|
||||
add_ball(s,0,0,0, 0,0,1, 0.2, 6);
|
||||
for (int i=0;i<nd;i++){
|
||||
double tx=d[i][0], ty=d[i][1], tz=d[i][2];
|
||||
int tip=s->nv; PV(s,tx,ty,tz,0,0,0); AE(s,c,tip);
|
||||
add_ball(s,tx,ty,tz,d[i][0],d[i][1],d[i][2],0.17,6);
|
||||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* diabolo / hourglass burst: two cones tip-to-tip with a waisted lattice */
|
||||
static void gen_diabolo3d(int nspokes) {
|
||||
Solid *s=new_solid(3);
|
||||
int top=s->nv; PV(s,0,0,1.0,0,0,0);
|
||||
int bot=s->nv; PV(s,0,0,-1.0,0,0,0);
|
||||
int rt=s->nv; for(int i=0;i<nspokes;i++){ double a=TAU*i/nspokes; PV(s,0.6*cos(a),0.6*sin(a),0.35,0,0,0); }
|
||||
int rb=s->nv; for(int i=0;i<nspokes;i++){ double a=TAU*i/nspokes; PV(s,0.6*cos(a),0.6*sin(a),-0.35,0,0,0); }
|
||||
for (int i=0;i<nspokes;i++){
|
||||
AE(s,top,rt+i); AE(s,bot,rb+i);
|
||||
AE(s,rt+i,rt+(i+1)%nspokes); AE(s,rb+i,rb+(i+1)%nspokes);
|
||||
AE(s,rt+i,rb+i);
|
||||
}
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* planar ray starburst with a pair of axial spikes for 3-D pop */
|
||||
static void gen_raystar3d(int nrays) {
|
||||
Solid *s=new_solid(3);
|
||||
int c=s->nv; PV(s,0,0,0,0,0,0);
|
||||
for (int i=0;i<nrays;i++){ double a=TAU*i/nrays, r=(i&1)?0.6:1.0;
|
||||
int tip=s->nv; PV(s,r*cos(a),r*sin(a),0,0,0,0); AE(s,c,tip); }
|
||||
int z1=s->nv; PV(s,0,0,0.7,0,0,0); AE(s,c,z1);
|
||||
int z2=s->nv; PV(s,0,0,-0.7,0,0,0); AE(s,c,z2);
|
||||
center_normalize(s);
|
||||
}
|
||||
|
||||
/* ---- expressive faces and the '@' sign (flat + extruded) ---------- */
|
||||
|
||||
static void build_frowny(SymB *b) {
|
||||
sym_ring(b, 0,0, 1.0, 18);
|
||||
sym_ring(b, -0.35, 0.32, 0.12, 6);
|
||||
sym_ring(b, 0.35, 0.32, 0.12, 6);
|
||||
sym_arc (b, 0.0, -0.55, 0.5, sym_deg(20), sym_deg(160), 8); /* downturned mouth */
|
||||
}
|
||||
static void build_angry(SymB *b) {
|
||||
sym_ring(b, 0,0, 1.0, 18);
|
||||
sym_ring(b, -0.33, 0.26, 0.11, 6);
|
||||
sym_ring(b, 0.33, 0.26, 0.11, 6);
|
||||
sym_line(b, -0.58, 0.62, -0.14, 0.42); /* angry V brows: inner ends low */
|
||||
sym_line(b, 0.58, 0.62, 0.14, 0.42);
|
||||
sym_arc (b, 0.0, -0.58, 0.48, sym_deg(20), sym_deg(160), 8); /* frown */
|
||||
}
|
||||
static void build_at(SymB *b) {
|
||||
sym_arc (b, 0.0, 0.0, 1.0, sym_deg(-25), sym_deg(295), 20); /* outer ring, open at right */
|
||||
sym_ring(b, -0.05, 0.0, 0.40, 12); /* inner 'a' bowl */
|
||||
sym_line(b, 0.35, 0.42, 0.35, -0.55); /* 'a' stem / tail */
|
||||
}
|
||||
|
||||
/* ---- pop-culture / object iconography (flat 2-D + extruded 3-D) ---- */
|
||||
|
||||
static void build_invader(SymB *b) { /* blocky pixel-alien (Space Invader) */
|
||||
const double body[] = {
|
||||
-0.7, 0.2, -0.7,-0.2, -0.5,-0.2, -0.5,-0.5, -0.25,-0.5, -0.25,-0.25,
|
||||
0.25,-0.25, 0.25,-0.5, 0.5,-0.5, 0.5,-0.2, 0.7,-0.2, 0.7, 0.2,
|
||||
0.45,0.5, 0.2,0.5, 0.2,0.78, 0.05,0.78, 0.05,0.5, -0.05,0.5,
|
||||
-0.05,0.78, -0.2,0.78, -0.2,0.5, -0.45,0.5 };
|
||||
sym_poly(b, body, 22, 1);
|
||||
sym_ring(b, -0.25, 0.12, 0.08, 5);
|
||||
sym_ring(b, 0.25, 0.12, 0.08, 5);
|
||||
}
|
||||
static void build_ufo(SymB *b) { /* flying saucer */
|
||||
sym_ellipse(b, 0,0, 1.0, 0.30, 0, 22); /* saucer disc */
|
||||
sym_arc(b, 0.0, 0.06, 0.46, sym_deg(0), sym_deg(180), 11); /* dome */
|
||||
for (int i=-2;i<=2;i++) sym_ring(b, i*0.32, -0.22, 0.05, 4); /* lights */
|
||||
}
|
||||
static void build_pacman(SymB *b) { /* wedge-mouth + pellet */
|
||||
sym_arc(b, 0,0, 1.0, sym_deg(36), sym_deg(324), 24);
|
||||
int last = b->np - 1, c = sym_pt(b, 0, 0);
|
||||
sym_edge(b, last, c); sym_edge(b, c, 0); /* close the mouth wedge */
|
||||
sym_ring(b, 0.05, 0.45, 0.09, 5); /* eye */
|
||||
sym_ring(b, 1.35, 0.0, 0.12, 6); /* pellet */
|
||||
}
|
||||
static void build_alien(SymB *b) { /* grey alien head */
|
||||
int seg=22, first=-1, prev=-1;
|
||||
for (int i=0;i<seg;i++){
|
||||
double a=TAU*i/seg, x=0.62*cos(a), y=sin(a);
|
||||
if (y<0) x *= (1.0 + y*0.42); /* taper to a chin */
|
||||
int idx=sym_pt(b, x, y>0 ? y*0.95 : y*1.28);
|
||||
if(first<0)first=idx;
|
||||
if(prev>=0)sym_edge(b,prev,idx);
|
||||
prev=idx;
|
||||
}
|
||||
sym_edge(b, prev, first);
|
||||
sym_ellipse(b, -0.26, 0.05, 0.22, 0.10, sym_deg( 28), 9); /* almond eyes */
|
||||
sym_ellipse(b, 0.26, 0.05, 0.22, 0.10, sym_deg(-28), 9);
|
||||
}
|
||||
static void build_pipe(SymB *b) { /* smoking pipe */
|
||||
sym_arc(b, -0.55, 0.0, 0.34, sym_deg(18), sym_deg(342), 14); /* bowl, open at top */
|
||||
const double stem[] = { -0.28,-0.22, 0.2,-0.32, 0.7,-0.3, 0.98,-0.18 };
|
||||
sym_poly(b, stem, 4, 0);
|
||||
sym_line(b, 0.98,-0.18, 1.04,-0.04); /* mouthpiece */
|
||||
}
|
||||
static void build_umbrella(SymB *b) { /* canopy + ribs + pole + J-handle */
|
||||
double R = 0.95; int n = 4;
|
||||
sym_arc(b, 0, 0.0, R, sym_deg(0), sym_deg(180), 14); /* canopy dome */
|
||||
for (int i=0;i<n;i++){ /* scalloped hem */
|
||||
double x0=-R+2*R*i/n, x1=-R+2*R*(i+1)/n, xm=(x0+x1)/2;
|
||||
sym_arc(b, xm, 0.0, (x1-x0)/2, sym_deg(180), sym_deg(360), 4);
|
||||
}
|
||||
for (int i=0;i<=n;i++) sym_line(b, 0, R, -R+2*R*i/n, 0.0); /* ribs */
|
||||
sym_line(b, 0, 0.0, 0, -0.85); /* pole */
|
||||
sym_arc (b, -0.12, -0.85, 0.12, sym_deg(0), sym_deg(-180), 6); /* handle */
|
||||
}
|
||||
static void build_hand(SymB *b) { /* open hand silhouette */
|
||||
const double hand[] = {
|
||||
-0.45,-0.9, -0.5,-0.2, -0.85,0.1, -0.78,0.38, -0.45,0.08,
|
||||
-0.4,0.72, -0.29,0.98, -0.18,0.66,
|
||||
-0.12,0.82, 0.0,1.06, 0.09,0.74,
|
||||
0.14,0.8, 0.27,1.0, 0.35,0.68,
|
||||
0.41,0.62, 0.52,0.82, 0.56,0.5,
|
||||
0.46,-0.9 };
|
||||
sym_poly(b, hand, 18, 1);
|
||||
}
|
||||
|
||||
/* ---- live clocks (rebuilt every frame from the current local time) ---- */
|
||||
|
||||
/* one seven-segment digit in a cell of width w and height 2h at (ox,oy) */
|
||||
static void sym_7seg(SymB *b, int dg, double ox,double oy,double w,double h) {
|
||||
int TL=sym_pt(b,ox,oy+2*h), TR=sym_pt(b,ox+w,oy+2*h);
|
||||
int ML=sym_pt(b,ox,oy+h), MR=sym_pt(b,ox+w,oy+h);
|
||||
int BL=sym_pt(b,ox,oy), BR=sym_pt(b,ox+w,oy);
|
||||
static const unsigned char seg[10] =
|
||||
{ 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F };
|
||||
int m = seg[dg % 10];
|
||||
if(m&0x01) sym_edge(b,TL,TR); /* a top */
|
||||
if(m&0x02) sym_edge(b,TR,MR); /* b up-right */
|
||||
if(m&0x04) sym_edge(b,MR,BR); /* c lo-right */
|
||||
if(m&0x08) sym_edge(b,BL,BR); /* d bottom */
|
||||
if(m&0x10) sym_edge(b,ML,BL); /* e lo-left */
|
||||
if(m&0x20) sym_edge(b,TL,ML); /* f up-left */
|
||||
if(m&0x40) sym_edge(b,ML,MR); /* g middle */
|
||||
}
|
||||
static void build_analog(SymB *b, const struct tm *lt) {
|
||||
sym_ring(b, 0,0, 1.0, 24); /* face */
|
||||
for (int i=0;i<12;i++){ /* hour ticks */
|
||||
double a=TAU*i/12;
|
||||
sym_line(b, 0.86*cos(a),0.86*sin(a), 0.97*cos(a),0.97*sin(a));
|
||||
}
|
||||
int h=lt->tm_hour%12, m=lt->tm_min, s=lt->tm_sec;
|
||||
double ha=TAU*0.25 - TAU*((h + m/60.0)/12.0); /* 12 at top, clockwise */
|
||||
double ma=TAU*0.25 - TAU*(m/60.0);
|
||||
double sa=TAU*0.25 - TAU*(s/60.0);
|
||||
int c=sym_pt(b,0,0);
|
||||
sym_edge(b, c, sym_pt(b, 0.50*cos(ha), 0.50*sin(ha))); /* hour */
|
||||
sym_edge(b, c, sym_pt(b, 0.74*cos(ma), 0.74*sin(ma))); /* minute */
|
||||
sym_edge(b, c, sym_pt(b, 0.84*cos(sa), 0.84*sin(sa))); /* second */
|
||||
}
|
||||
static void build_digital(SymB *b, const struct tm *lt) {
|
||||
int hh=lt->tm_hour, mm=lt->tm_min, d[4]={hh/10,hh%10,mm/10,mm%10};
|
||||
double w=0.30, h=0.30, cw=0.42, oy=-0.3;
|
||||
double x[4]={-0.92,-0.92+cw, 0.18, 0.18+cw};
|
||||
for (int i=0;i<4;i++) sym_7seg(b, d[i], x[i], oy, w, h);
|
||||
sym_ring(b, -0.02, oy+0.42*h, 0.035, 4); /* colon dots */
|
||||
sym_ring(b, -0.02, oy+1.4*h, 0.035, 4);
|
||||
const double fr[]={-1.12,-0.55, 1.12,-0.55, 1.12,0.55, -1.12,0.55};
|
||||
sym_poly(b, fr, 4, 1); /* bezel keeps size constant */
|
||||
}
|
||||
/* Rewrite the four clock solids in place from the current local time. */
|
||||
static void update_clocks(void) {
|
||||
if (clock_idx[0] < 0) return;
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
SymB b;
|
||||
sym_init(&b); build_analog (&b, lt); sym_fill_solid(&solids[clock_idx[0]], &b, 0.0f);
|
||||
sym_init(&b); build_analog (&b, lt); sym_fill_solid(&solids[clock_idx[1]], &b, 0.5f);
|
||||
sym_init(&b); build_digital(&b, lt); sym_fill_solid(&solids[clock_idx[2]], &b, 0.0f);
|
||||
sym_init(&b); build_digital(&b, lt); sym_fill_solid(&solids[clock_idx[3]], &b, 0.5f);
|
||||
}
|
||||
|
||||
/* Build a symbol in both its flat and extruded-3-D forms. */
|
||||
static void add_symbol(void (*build)(SymB *)) {
|
||||
SymB b;
|
||||
|
|
@ -764,6 +1108,59 @@ static void init_solids(void) {
|
|||
add_symbol(build_dollar); /* dollar sign */
|
||||
add_symbol(build_sterling); /* pound sterling (£) */
|
||||
|
||||
/* --- 30+ more googie / atomic-age 3-D objects --- */
|
||||
gen_burst3d(0, 1.0, 0.0, 0); /* 6-spike asterisk star */
|
||||
gen_burst3d(1, 1.0, 0.0, 0); /* 8-spike cube burst */
|
||||
gen_burst3d(2, 1.0, 0.55, 0); /* 12-spike spiky star */
|
||||
gen_burst3d(3, 1.0, 0.0, 0); /* 20-spike sea urchin */
|
||||
gen_burst3d(4, 1.0, 0.6, 0); /* 32-spike dense urchin */
|
||||
gen_burst3d(4, 1.0, 0.0, 0); /* 32-spike uniform urchin */
|
||||
gen_burst3d(2, 1.0, 0.0, 1); /* 12 ball-tipped sputnik */
|
||||
gen_burst3d(0, 1.0, 0.0, 1); /* 6 ball-tipped jacks */
|
||||
gen_burst3d(1, 1.0, 0.0, 1); /* 8 ball-tipped burst */
|
||||
gen_burst3d(3, 1.0, 0.0, 1); /* 20 ball-tipped burst */
|
||||
gen_burst3d(2, 1.0, 0.4, 1); /* 12 alt ball-tipped burst */
|
||||
gen_rings3d(2, 24); /* crossed rings */
|
||||
gen_rings3d(3, 22); /* gyroscope */
|
||||
gen_rings3d(4, 20); /* 4-ring cage */
|
||||
gen_rings3d(5, 20); /* 5-ring cage */
|
||||
gen_rings3d(6, 20); /* 6-ring orb cage */
|
||||
gen_atomorbits(2, 24); /* 2-orbit atom */
|
||||
gen_atomorbits(4, 20); /* 4-orbit atom */
|
||||
gen_atomorbits(5, 18); /* 5-orbit atom */
|
||||
gen_atomorbits(6, 16); /* 6-orbit atom */
|
||||
gen_saturn3d(1, 0.0); /* ringed planet */
|
||||
gen_saturn3d(2, 0.35); /* double-ringed planet */
|
||||
gen_saturn3d(1, 0.6); /* tilted-ring planet */
|
||||
gen_molecule3d(0); /* octahedral molecule */
|
||||
gen_molecule3d(1); /* cubic molecule */
|
||||
gen_molecule3d(2); /* icosahedral molecule */
|
||||
gen_diabolo3d(6); /* hex diabolo */
|
||||
gen_diabolo3d(10); /* diabolo / hourglass */
|
||||
gen_diabolo3d(16); /* fine diabolo */
|
||||
gen_raystar3d(12); /* 12-ray starburst */
|
||||
gen_raystar3d(16); /* 16-ray starburst */
|
||||
gen_raystar3d(24); /* 24-ray sunburst */
|
||||
|
||||
/* --- expressive faces + the @ sign (flat 2-D and extruded 3-D) --- */
|
||||
add_symbol(build_angry); /* angry face */
|
||||
add_symbol(build_frowny); /* frowny face */
|
||||
add_symbol(build_at); /* at sign (@) */
|
||||
|
||||
/* --- object iconography (flat 2-D and extruded 3-D each) --- */
|
||||
add_symbol(build_invader); /* space invader */
|
||||
add_symbol(build_ufo); /* flying saucer */
|
||||
add_symbol(build_pacman); /* pac-man */
|
||||
add_symbol(build_alien); /* alien head */
|
||||
add_symbol(build_pipe); /* smoking pipe */
|
||||
add_symbol(build_umbrella); /* umbrella */
|
||||
add_symbol(build_hand); /* hand */
|
||||
|
||||
/* --- live clocks: reserve 4 slots, then fill from the current time
|
||||
* (refreshed every frame by update_clocks() in the main loop) --- */
|
||||
for (int i = 0; i < 4; i++) { clock_idx[i] = num_shapes; new_solid(3); }
|
||||
update_clocks();
|
||||
|
||||
/* --- 4/5/6-dimensional polytopes (projected & morphing) --- */
|
||||
gen_simplex(5); /* 5-cell (4-simplex) */
|
||||
gen_hypercube(4); /* tesseract / 8-cell */
|
||||
|
|
@ -1498,6 +1895,7 @@ int main(void) {
|
|||
|
||||
int active = active_count();
|
||||
ensure_filled(active);
|
||||
update_clocks(); /* keep the clock shapes showing the current time */
|
||||
|
||||
for (int i = 0; i < active; i++) {
|
||||
Body *b = &bodies[i];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue