qr code

BIT-101

Bill Gates touched my MacBook Pro

Wire: Part III - Evolution


[ code , golang , creative-coding ]

I’ve been a bit quiet here, but have been very much heads down working on this wire library. I refactored (or more correctly, rewrote) a lot of the core code and added a bunch of new features.

Code Changes

Points and Paths

The biggest fundamental change is in how I store paths. Many objects consist of multiple paths. Consider this torus:

Each ring in the torus is a single path composed of a list of points that is stroked. Initially, I stored each path as a separate list of 3d points and then projected those points and stroked a line between each point in the path. This was a good way to get started, but problems cropped up. Imagine a 3d cube. There’s no way to draw it in a single path without overlapping, so you get multiple paths, but no matter how you arrange it, you’re going to need to use the same point in multiple paths. I have a set of randomize functions that randomly moves each point to shake up the shape. This meant that those shared points would diverge and the cube would break apart. You might try to share the same actual point object in multiple paths, but then when you transform the shape, you’d be transforming some points multiple times.

Also, having a list of points as a path turned out to be not so useful. When I draw each path, I scale the width of each line segment in the path and draw it separately to make sure each one is scaled separately. So it’s moveto, lineto, stroke, moveto, lineto, stroke, ... rather than moveto, lineto, lineto, lineto, ..., stroke.

Due to these (and other) issues, I changed each shape to have a single list of points and a single list of segments. A segment connects two points. This was a pretty extensive refactor, but simplified a lot and has proven to be well worth it. In the cube example, there are only eight points, and twelve segments connecting them. Transformations and randomizations just affect those eight points and each segment continues to connect the same two points, so it all works out well.

Operations like cloning a shape did become a bit more complex. Rather than just cloning each separate path, I had to clone the list of points, and then make a new segment list that connected the correct pairs of points. It might have been easier if segments contained two indices to points rather than references to point objects, but I’m glad I kept it that way because it made other operations easier.

Colors and Z-sorting

I toyed with the idea of having each point contain its own color. This required z-sorting the list of points before drawing them. I got it working for drawing points, but realized that drawing segments this way was going to be more complex. And then, to draw multiple shapes, you’d have to pool all the points and segments and z-sort them all together and draw them in order.

In the end I decided I liked the constraint of monochrome. So I removed the color and z-sorting code. It might come back at some point, but I’m happy with the decision for now.

Fog

I implemented fog. This just sets a nearFog and farFog value and linearly interpolates between them, changing the drawing alpha. Anything with a z value less than or equal to nearFog is drawn with full opacity. Anything further away than farFog gets zero opacity. This is a nice effect that was pretty easy to create.

World

I updated this world singleton so all client operations on it are via methods.

Shape Updates

I updated a bunch of shapes. In particular, the sphere now has options to draw latitude lines, longitude lines, or both.

The cylinder, cone and torus have similar options.

I also added a couple of new shapes, grid plane and spring.

Finally, there is now a way to combine shapes using shape.AddShape(otherShape). This simply appends the points and segments onto the points and segments of the parent shape. Amazingly simple, but now you have a single, complex shape that you can transform and draw simply. This is one area where I’m glad I kept segments containing references to points, not indices to points. Doing it this way means I can just append the new segments to the existing segments, not have to worry about re-indexing them.

There are a few other goodies I threw in there as well, but I’ll probably cover those later.

A New(ly updated) Site!

A bit of a teaser here as I’ll have another post on this soon, but I updated my artfromcode.com site and it has a bunch of neat wire examples there so far. Been working on updating it daily.

« Previous Post
Next Post »

Comments? Best way to shout at me is on Mastodon

Or share this post directly on Mastodon