-
Notifications
You must be signed in to change notification settings - Fork 2
/
showcase.pbd
187 lines (173 loc) · 7.16 KB
/
showcase.pbd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/*
* Prettybird Language Showcase
*/
/*
* Prettybird fonts are generated by declaring characters, like below.
* This is the character declaration for lowercase "c".
*/
char c {
/*
* The first step is to declare the character's "base".
* The base defines how big the character should be,
* blank(24, 36) means "set up a blank space with a
* width of 24 and a height of 36"
*/
base {
blank(24, 36)
}
/*
* After this, it's time to draw our glyph! Prettybird
* supports a list of "atoms", or fundamental building blocks
* for drawing glyphs. These are "vector", "ellipse", "rectangle",
* and "bezier". Additionally, we've included "point", "circle",
* and "square" as a convenience, which can be derived from the
* atoms. We'll talk about each of these individually.
*/
steps {
/*
* Here, we *draw* a circle with a center at (x, y) = (12, 12)
* and a radius of 8. In Prettybird, the grid you draw on
* grows rightward as x increases, and downward as y increases.
* So, (6, 6) would be in the top-left corner of our glyph's
* grid, and (18, 18) would be in the bottom-right corner.
*/
draw circle((12, 12), 8)
/*
* Here, we *erase* a *filled* circle, with a center at
* (x, y) = (18, 12) and a radius of 8. This essentially takes
* a chunk out of the cicle that we just drew, a chunk that is
* to the right of the glyph. This removes an arc on the first
* circle, leaving us with a crescent denoting the character "c"
*/
erase filled circle ((18, 12), 8)
}
}
/*
* That simple example was nice, but doesn't show off the power of the language.
* This is a function, a chunk of reusable code that characters can call to modify
* their glyph spaces. Functions have their own glyph space, so you don't have to
* worry about overwriting any of your existing creations. When a function terminates,
* it will overlay its glyph space onto your character's glyph space.
*
* Functions have "parameters", in this case they are "left_center", "right_center",
* and "radius". You need to pass values (points or numbers) into these parameters
* when you call the function, and this lets you perform arbitrary operations
* given different sets of inputs.
*
*
* Functions are cool specifically because they can be reused. This makes it easier to
* apply font pieces like serifs over and over. This function is simpler, and will just draw
* two circles on top of one another, creating a figure eight shape.
*/
define figure_eight(top_center, radius) {
draw circle(top_center, radius)
/*
* In this line, we add the point "top_center" to a point we
* create on the spot. It can be noted that we're multiplying
* the "radius" number by 2, and putting it in the Y spot
* of our point. This ensures that this bottom circle's center
* will be offset from "top_center" by a factor of (2 * radius)
*/
draw circle(top_center + (0, 2 * radius), radius)
}
/*
* Let's use this function to draw our "8" character
*/
char 8 {
base {
blank(24, 24)
}
steps {
/*
* Let's call our figure_eight function with the top circle's
* center at (8, 8), and with both circles having radius 4
*/
figure_eight((8, 8), 4)
/*
* We could put this figure eight anywhere, and with any radius!
* The following line is commented, so it won't run, but you can
* comment out the line above to try it out. Here's a smaller
* eight, with circles of radius 2
*/
//figure_eight((8, 8), 2)
}
}
/*
* That was cool! but you can do so much more with functions. For example,
* functions can call themselves! We call this "recursion". Recursion
* is one of the strong points of Prettybird, as you can create intricate
* designs without manually designing them. This function draws a square
* spiral from the outside in. It's a little complicated and uses a bit of
* math, so let's explain it.
*/
define draw_square_spiral(start_point, length, x_direction, y_direction) {
/*
* Looking at the function parameters, we have a start point
* for our spiral, a "length" value that determines how long
* this segment of the spiral will be, and an X direction and Y direction.
* Those last two values determine which way the next segment
* of the spiral will go: a negative X direction means left,
* positive X direction means right, negative Y means up,
* and positive Y means down.
*/
/*
* When dealing with recursion, we want to have some sort of "base case"
* that will stop the function from calling itself if a condition is met.
* This line uses the "stop" keyword to stop the function, but only if
* the length of the current segment of the spiral is 0.
*/
stop if length <= 0
/*
* This is the meat of the function. Here, we draw a line segment (vector)
* starting at start_point, and terminating at an offset from start_point
* that changes based on what direction we're going in on this iteration.
* The "%" operator might be unfamiliar, it is called "modulo" or "mod",
* and means "give me the remainder of the division between these two
* numbers". So, given length=4, "(length % 2)" evaluates to 4 % 2. The remainder
* of 4 / 2 is 0, so 4 % 2 = 0. But, in "((length - 1) % 2)", we get
* 3 % 2. The remainder of 3 / 2 is 1, so 3 % 2 = 1.
*/
draw vector(start_point,
start_point + (x_direction * length * (length % 2),
y_direction * length * ((length - 1) % 2))
)
/*
* And here's the recursive call. See that we're calling the same function
* that we're currently in. We take the endpoint that we just computed,
* and we pass it into the new function as start_point. Then, we subtract
* 1 from length, because the next leg of this spiral should be shorter, and
* pass that value into the new length. Then, we'll update the x and y directions,
* swapping between -1 and 1 on every iteration.
*/
draw_square_spiral(
start_point + (x_direction * length * (length % 2),
y_direction * length * ((length - 1) % 2)),
length - 1,
x_direction * (1 - (2 * (length % 2))),
y_direction * (1 - (2 * ((length - 1) % 2)))
)
}
/*
* And that's it! It's complicated, but this allows you to create intricate patterns
* for your fonts. Knowing how to work with recursion is a powerful tool. Let's draw
* this square spiral onto our "o" character. It'll look a little silly, but that's
* okay.
*/
char o {
base {
blank(24, 24)
}
steps {
// Let's start our spiral at (1, 1), with a length of 21
draw_square_spiral((1, 1), 21, 1, 1)
}
}
/*
* And that's the showcase! It only
* has the characters "c", "o", and "8", but
* the compiler will generate a valid font file
* that you can use on the internet, in documents,
* anywhere! Run the following command to generate a TTF file:
*
* prettybird examples/showcase.pbd
*/