XXIIVV
Moogle on Plan 9
Moogle on Plan 914T03

Moogle is a wireframe editor.

Moogle is a minimal 3D wireframe tool designed to be used alongside its companion tool Noodle, both can export to the icn format. It offers a handful of basic geometry drawing functions, it was written in ANSI C, and was inspired by Graf3DScene.

ANSI C

Creating wireframe scenes is done by modifying the program's source code.

cc -Os -DNDEBUG -g0 -s -Wall -L/usr/local/lib -lSDL2 -lm moogle.c -o moogle

Plan9 C

Moogle was first written on Plan9, the original Plan9 C implementation is available here:

5c moogle.c && 5l -o moogle moogle.5

Structures

Mesh *
createdoorway(Scene *s, double width, double height, double depth, int color)
{
	Mesh *doorway = addmesh(s);
	Point3d a = Pt3d(-width, 0, 0),
			b = Pt3d(-width, height, 0),
			c = Pt3d(0, height + width, 0),
			d = Pt3d(width, height, 0),
			e = Pt3d(width, 0, 0);
	addline(doorway, a, b, color);
	addline(doorway, b, c, color);
	addline(doorway, c, d, color);
	addline(doorway, d, e, color);
	addline(doorway, e, a, color);
	extrude(doorway, 0, 0, depth, color);
	return doorway;
}

Mesh *
createstairs(Scene *s, double width, int steps, int color)
{
	int i;
	Point3d a, b, c, d;
	Mesh *stairs = addmesh(s);
	for(i = 0; i < steps; ++i) {
		a = Pt3d(-width, i + 1, i), b = Pt3d(width, i + 1, i), c = Pt3d(-width, i + 1, 1 + i), d = Pt3d(width, i + 1, 1 + i);
		addline(stairs, a, b, color);
		addline(stairs, c, d, color);
		addline(stairs, a, c, color);
		addline(stairs, b, d, color);
		addline(stairs, a, Pt3d(a.x, a.y - 1, a.z), color);
		addline(stairs, b, Pt3d(b.x, b.y - 1, b.z), color);
	}
	addline(stairs, c, Pt3d(c.x, 0, c.z), color);
	addline(stairs, d, Pt3d(d.x, 0, d.z), color);
	addline(stairs, Pt3d(c.x, 0, c.z - steps), Pt3d(c.x, 0, c.z), color);
	addline(stairs, Pt3d(d.x, 0, d.z - steps), Pt3d(d.x, 0, d.z), color);
	return stairs;
}

Mesh *
createring(Scene *s, double radius, double thickness, double depth, int segs, double angle, int color)
{
	Mesh *ring = addmesh(s);
	/* front */
	addarc(ring, radius, segs, angle, color);
	addarc(ring, radius + thickness, segs, angle, color);
	addedge(ring, ring->vertices, ring->vertices + segs + 1, color);
	addedge(ring, ring->vertices + segs, ring->vertices + segs * 2 + 1, color);
	/* back */
	moveto(s, 0, 0, depth);
	addarc(ring, radius, segs, angle, color);
	addarc(ring, radius + thickness, segs, angle, color);
	addedge(ring, ring->vertices + segs * 3 + 2, ring->vertices + segs * 4 + 3, color);
	addedge(ring, ring->vertices + segs * 2 + 2, ring->vertices + segs * 3 + 3, color);
	/* connects */
	addedge(ring, ring->vertices, ring->vertices + segs * 2 + 2, color);
	addedge(ring, ring->vertices + segs, ring->vertices + segs * 3 + 2, color);
	addedge(ring, ring->vertices + segs + 1, ring->vertices + segs * 3 + 3, color);
	addedge(ring, ring->vertices + segs * 2 + 1, ring->vertices + segs * 4 + 3, color);
	reset(s);
	return ring;
}

Mesh *
createblast(Scene *s, double radius, double density, double seed, int color)
{
	int i;
	Mesh *blast = addmesh(s);
	for(i = 0; i < density; ++i) {
		addline(blast,
			Pt3d(radius - cos(i) * radius / 2, 0, 0),
			Pt3d(radius, 0, 0),
			color);
		rotateto(s,
			tan(i) * seed,
			sin(i) * seed * density,
			sin(i) * seed + seed);
	}
	reset(s);
	return blast;
}

Line2d

typedef struct {
Point2d a, b;
} Line2d;

double
slope2d(Line2d l0)
{
if(l0.a.x - l0.b.x == 0.0)
return 0;
return (l0.a.y - l0.b.y) / (l0.a.x - l0.b.x);
}

Point2d
normal2d(Line2d l0)
{
Point2d normal = Pt2d(l0.a.y - l0.b.y, l0.b.x - l0.a.x);
double normalLength = sqrt(normal.x * normal.x + normal.y * normal.y);
normal.x /= normalLength;
normal.y /= normalLength;
return normal;
}

double
parallel2d(Line2d l0, Line2d l1)
{
return slope2d(l0) == slope2d(l1);
}

int
intersect2d(Line2d l0, Line2d l1, Point2d *p0)
{
double den, ua, ub;
if((l0.a.x == l0.b.x && l0.a.y == l0.b.y))
return 0;
if((l1.a.x == l1.b.x && l1.a.y == l1.b.y))
return 0;
den = ((l1.b.y - l1.a.y) * (l0.b.x - l0.a.x) - (l1.b.x - l1.a.x) * (l0.b.y - l0.a.y));
if(den == 0)
return 0;
ua = ((l1.b.x - l1.a.x) * (l0.a.y - l1.a.y) - (l1.b.y - l1.a.y) * (l0.a.x - l1.a.x)) / den;
ub = ((l0.b.x - l0.a.x) * (l0.a.y - l1.a.y) - (l0.b.y - l0.a.y) * (l0.a.x - l1.a.x)) / den;
if(ua < 0 || ua > 1 || ub < 0 || ub > 1)
return 0;
p0->x = l0.a.x + ua * (l0.b.x - l0.a.x);
p0->y = l0.a.y + ua * (l0.b.y - l0.a.y);
return 1;
}

void
extend2d(Line2d l0, Point2d *p0, int len)
{
double lenAB = sqrt(pow(l0.a.x - l0.b.x, 2.0) + pow(l0.a.y - l0.b.y, 2.0));
p0->x = l0.b.x + (l0.b.x - l0.a.x) / lenAB * len;
p0->y = l0.b.y + (l0.b.y - l0.a.y) / lenAB * len;
}

Point2d.

typedef struct {
int x, y;
} Point2d;

Point2d *
setpt2d(Point2d *p, int x, int y)
{
p->x = x;
p->y = y;
return p;
}

Point2d
Pt2d(int x, int y)
{
Point2d p;
setpt2d(&p, x, y);
return p;
}

Point2d
mid2d(Point2d a, Point2d b, int seg, int segs)
{
return Pt2d(
a.x + ((b.x - a.x) / (double)segs) * seg,
a.y + ((b.y - a.y) / (double)segs) * seg);
}

Point2d *
mag2d(Point2d *a, int step)
{
return setpt2d(a,
abs(a->x / step) * step,
abs(a->y / step) * step);
}

int
equ2d(Point2d *a, Point2d *b)
{
return a->x == b->x && a->y == b->y;
}

int
distance2d(Point2d p0, Point2d p1)
{
double a = p0.x - p1.x, b = p0.x - p1.x;
return sqrt(a * a + b * b);
}

int
collinear2d(Point2d a, Point2d b, Point2d c)
{
return (b.y - a.y) * (c.x - b.x) - (c.y - b.y) * (b.x - a.x);
}
Moogle Spheroid
Moogle Spheroid14P00

incoming: visual faqs graf3dscene identity 2021 goals