Skip to content

Commit a1ee3ca

Browse files
committed
[feat] add freetype bindings
1 parent 3437a4a commit a1ee3ca

File tree

4 files changed

+801
-15
lines changed

4 files changed

+801
-15
lines changed

README.md

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ This repository contains external libraries for use with C3.
1313
- PQ (PostgreSQL) https://www.postgresql.org/docs/current/libpq.html
1414
- MySQL 8 https://dev.mysql.com/doc/c-api/8.0/en/
1515
- SQLite 3 https://sqlite.com/c3ref/intro.html
16+
- FreeType https://freetype.org/ - WIP
1617

1718
## Guide for writing bindings
1819

@@ -23,13 +24,13 @@ rewritten to work in C3, and one also have to consider the namespacing C3 will a
2324

2425
1. Keep names predicable so that a user who knows the name in C can easily find the name in C3.
2526
2. Avoid changing the names to conform to some other style, even if it's the C3 standard. By keeping the original name it's much
26-
easier to drop in code examples and to see exactly what is the library code. Users can write 'C3-like' wrappers later,
27+
easier to drop in code examples and to see exactly what is the library code. Users can write 'C3-like' wrappers later,
2728
but that can be added when the "raw" functions are already there.
2829

2930
### Module name
3031

3132
The user will use the last component in the module name you choose, shorter names
32-
are often appreciated, if possible. But also make sure that the full name
33+
are often appreciated, if possible. But also make sure that the full name
3334
is unique. `com::mylib::asyncio` is better than `asyncio`.
3435

3536
### Function names
@@ -57,16 +58,16 @@ options:
5758
When converting OS functions, then (1) is sometimes fine. Otherwise, prefer (2).
5859

5960
1. Don't change anything more about the name, at most add the prefix or change the first character to lower case.
60-
2. If (2) is used, pick a module name where the library source is immediately obvious.
61-
For example, imagine `module mylib::ui;` was used, and now `ui::openWindow(...)`
61+
2. If (2) is used, pick a module name where the library source is immediately obvious.
62+
For example, imagine `module mylib::ui;` was used, and now `ui::openWindow(...)`
6263
is suddenly super unclear.
6364
3. For bindings to OS libraries, use the name of the OS as the last module component,
6465
e.g. `module std::os::win32`, `module std::os::posix`, `module std::os::darwin` etc.
6566

6667
### Type names
6768

6869
Types will in general not be prefixed as long as they're unique,
69-
but if the library uses very common names, there is a risk for
70+
but if the library uses very common names, there is a risk for
7071
name collision.
7172

7273
#### Type names that are not valid C3 type names
@@ -103,7 +104,7 @@ types, then that type should be prefixed as well, so `Win32_Foo`.
103104

104105
For bindings that use `int`, `char` etc, there are two options:
105106

106-
1. Use `CInt`, `CChar` and others. This maximizes compatibility and allows
107+
1. Use `CInt`, `CChar` and others. This maximizes compatibility and allows
107108
the binding to be correct on platforms that might have 16-bit ints.
108109
2. Just use C3 `int` for `int`, `char` for `char`.
109110
3. Unless the sign of the `char` is important, replace C `char` by `char` and not `CChar`.
@@ -112,7 +113,7 @@ If it's known that the C type in the binding will always match the C3 size,
112113
then prefer (2) for that type.
113114

114115
For example, on MacOS and Win32 an `int` in C will always be the same size as in C3,
115-
so use `int` rather than `CInt` if you are making a binding for
116+
so use `int` rather than `CInt` if you are making a binding for
116117
OS libraries. However, the `long` in C may differ, so use `CLong` for that.
117118

118119
#### C strings (char *)
@@ -122,8 +123,8 @@ much more convenience for the user.
122123

123124
### Translating enums
124125

125-
For simple C enums that are implicitly sequential, i.e. they start at 0 with no break,
126-
C3 enums can be used unchanged. There is no need to set the type of the
126+
For simple C enums that are implicitly sequential, i.e. they start at 0 with no break,
127+
C3 enums can be used unchanged. There is no need to set the type of the
127128
enum as C3 enum sizes will default to C int size. So use `enum Foo { ... }`
128129
not `enum Foo : int { ... }`.
129130

@@ -136,7 +137,7 @@ my_constant -> MY_CONSTANT
136137
MyConstant -> MY_CONSTANT
137138
```
138139

139-
If simple enums are used, then (consistently for the entire binding)
140+
If simple enums are used, then (consistently for the entire binding)
140141
pick one of the following:
141142

142143
1. Remove any namespacing prefix, but don't remove suffixes. (Usually recommended)
@@ -161,7 +162,7 @@ enum Button
161162
{
162163
ANY_TYPE,
163164
CANCEL_TYPE,
164-
}
165+
}
165166
// 2. Full name:
166167
enum Button
167168
{
@@ -181,7 +182,7 @@ from simple to more complex.
181182

182183
##### Declaring a regular constant
183184

184-
This is simply
185+
This is simply
185186

186187
```c
187188
const GL_TEXTURE_2D = ...`
@@ -201,9 +202,9 @@ CInt / int.
201202

202203
##### Using a distinct type
203204

204-
In this case we first define a distinct type,
205+
In this case we first define a distinct type,
205206
matching the enum name, then use constant but with
206-
the distinct type. This is a better experience for
207+
the distinct type. This is a better experience for
207208
the user and is recommended.
208209

209210
The same recommendation regarding `@builtin`
@@ -236,7 +237,7 @@ We can model this as:
236237
// Define the distinct type
237238
distinct Button = CInt;
238239

239-
// Create a specific sub module based on the enum name
240+
// Create a specific sub module based on the enum name
240241
module mylib::ui::button;
241242

242243
// Place the constants inside

libraries/freetype.c3l/README.md

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# FreeType bindings
2+
3+
It is tested only on arm macos.
4+
5+
To make it work on other systems you need to add your platform to `manifest.json`, something like this:
6+
7+
```json
8+
"macos-aarch64": {
9+
// Extra flags to the linker for this target:
10+
"link-args": [
11+
"-I/opt/homebrew/opt/freetype/include/freetype2",
12+
"-L/opt/homebrew/opt/freetype/lib"
13+
],
14+
// C3 libraries this target depends on:
15+
"dependencies": [],
16+
// The external libraries to link for this target:
17+
"linked-libraries": [
18+
"freetype"
19+
]
20+
}
21+
```
22+
23+
`link-args` and `linked-libraries` can be found with this commands.
24+
25+
```bash
26+
$ freetype-config --libs
27+
-L/opt/homebrew/opt/freetype/lib -lfreetype
28+
$ freetype-config --cflags
29+
-I/opt/homebrew/opt/freetype/include/freetype2
30+
```
31+
32+
Note that `-L/opt/homebrew/opt/freetype/lib` goes to `link-args` and not to `linked-libraries`.
33+
34+
Here is a simple program that draws text in the terminal:
35+
36+
```cpp
37+
import freetype;
38+
import std::io;
39+
40+
fn int main() {
41+
mem::@report_heap_allocs_in_scope() {
42+
ft::Library library;
43+
defer ft::doneFreeType(library);
44+
ft::Face face;
45+
defer ft::doneFace(face);
46+
CInt err;
47+
48+
// init freetype lib
49+
err = ft::initFreeType(&library);
50+
if (err != 0) {
51+
io::printfn("init free type err: %s", ft::CINT_TO_ERROR[err]);
52+
return -1;
53+
}
54+
55+
// load face
56+
err = ft::newFace(library, "/Library/Fonts/Arial Unicode.ttf", 0, &face);
57+
if (err != 0) {
58+
io::printfn("can't load font: %s", ft::CINT_TO_ERROR[err]);
59+
return -1;
60+
}
61+
62+
// set font size
63+
err = ft::setPixelSizes(face, 80, 0);
64+
if (err != 0) {
65+
io::printfn("can't set pixel sizes: %s", ft::CINT_TO_ERROR[err]);
66+
return -1;
67+
}
68+
69+
err = ft::loadChar(face, 'A', ft::LOAD_RENDER);
70+
if (err != 0) {
71+
io::printfn("can't load char: %s", ft::CINT_TO_ERROR[err]);
72+
return -1;
73+
}
74+
75+
char[1024][1024] pixels;
76+
77+
for (int x = 0; x < face.glyph.bitmap.width; x++) {
78+
for (int y = 0; y < face.glyph.bitmap.rows; y++) {
79+
pixels[y][x] |= face.glyph.bitmap.buffer[y * face.glyph.bitmap.width + x];
80+
}
81+
}
82+
83+
for (int y = 0; y < face.glyph.bitmap.rows; y++) {
84+
for (int x = 0; x < face.glyph.bitmap.width; x++) {
85+
if (pixels[y][x] == 0) {
86+
io::printf(" ");
87+
} else if (pixels[y][x] < 128) {
88+
io::printf("+");
89+
} else {
90+
io::printf("*");
91+
}
92+
}
93+
io::printf("\n");
94+
}
95+
96+
97+
};
98+
99+
return 0;
100+
}
101+
```
102+
103+
You should get something like this:
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+
```

0 commit comments

Comments
 (0)