Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[feat] add freetype bindings #45

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This repository contains external libraries for use with C3.
- PQ (PostgreSQL) https://www.postgresql.org/docs/current/libpq.html
- MySQL 8 https://dev.mysql.com/doc/c-api/8.0/en/
- SQLite 3 https://sqlite.com/c3ref/intro.html
- FreeType https://freetype.org/ - WIP

## Guide for writing bindings

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

1. Keep names predicable so that a user who knows the name in C can easily find the name in C3.
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
easier to drop in code examples and to see exactly what is the library code. Users can write 'C3-like' wrappers later,
easier to drop in code examples and to see exactly what is the library code. Users can write 'C3-like' wrappers later,
but that can be added when the "raw" functions are already there.

### Module name

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

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

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

### Type names

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

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

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

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

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

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

### Translating enums

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

Expand All @@ -136,7 +137,7 @@ my_constant -> MY_CONSTANT
MyConstant -> MY_CONSTANT
```

If simple enums are used, then (consistently for the entire binding)
If simple enums are used, then (consistently for the entire binding)
pick one of the following:

1. Remove any namespacing prefix, but don't remove suffixes. (Usually recommended)
Expand All @@ -161,7 +162,7 @@ enum Button
{
ANY_TYPE,
CANCEL_TYPE,
}
}
// 2. Full name:
enum Button
{
Expand All @@ -181,7 +182,7 @@ from simple to more complex.

##### Declaring a regular constant

This is simply
This is simply

```c
const GL_TEXTURE_2D = ...`
Expand All @@ -201,9 +202,9 @@ CInt / int.

##### Using a distinct type

In this case we first define a distinct type,
In this case we first define a distinct type,
matching the enum name, then use constant but with
the distinct type. This is a better experience for
the distinct type. This is a better experience for
the user and is recommended.

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

// Create a specific sub module based on the enum name
// Create a specific sub module based on the enum name
module mylib::ui::button;

// Place the constants inside
Expand Down
162 changes: 162 additions & 0 deletions libraries/freetype.c3l/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# FreeType bindings

It is tested only on arm macos.

To make it work on other systems you need to add your platform to `manifest.json`, something like this:

```json
"macos-aarch64": {
// Extra flags to the linker for this target:
"link-args": [
"-I/opt/homebrew/opt/freetype/include/freetype2",
"-L/opt/homebrew/opt/freetype/lib"
],
// C3 libraries this target depends on:
"dependencies": [],
// The external libraries to link for this target:
"linked-libraries": [
"freetype"
]
}
```

`link-args` and `linked-libraries` can be found with this commands.

```bash
$ freetype-config --libs
-L/opt/homebrew/opt/freetype/lib -lfreetype
$ freetype-config --cflags
-I/opt/homebrew/opt/freetype/include/freetype2
```

Note that `-L/opt/homebrew/opt/freetype/lib` goes to `link-args` and not to `linked-libraries`.

Here is a simple program that draws text in the terminal:

```cpp
import freetype;
import std::io;

fn int main() {
mem::@report_heap_allocs_in_scope() {
ft::Library library;
defer ft::doneFreeType(library);
ft::Face face;
defer ft::doneFace(face);
CInt err;

// init freetype lib
err = ft::initFreeType(&library);
if (err != 0) {
io::printfn("init free type err: %s", ft::CINT_TO_ERROR[err]);
return -1;
}

// load face
err = ft::newFace(library, "/Library/Fonts/Arial Unicode.ttf", 0, &face);
if (err != 0) {
io::printfn("can't load font: %s", ft::CINT_TO_ERROR[err]);
return -1;
}

// set font size
err = ft::setPixelSizes(face, 80, 0);
if (err != 0) {
io::printfn("can't set pixel sizes: %s", ft::CINT_TO_ERROR[err]);
return -1;
}

err = ft::loadChar(face, 'A', ft::LOAD_RENDER);
if (err != 0) {
io::printfn("can't load char: %s", ft::CINT_TO_ERROR[err]);
return -1;
}

char[1024][1024] pixels;

for (int x = 0; x < face.glyph.bitmap.width; x++) {
for (int y = 0; y < face.glyph.bitmap.rows; y++) {
pixels[y][x] |= face.glyph.bitmap.buffer[y * face.glyph.bitmap.width + x];
}
}

for (int y = 0; y < face.glyph.bitmap.rows; y++) {
for (int x = 0; x < face.glyph.bitmap.width; x++) {
if (pixels[y][x] == 0) {
io::printf(" ");
} else if (pixels[y][x] < 128) {
io::printf("+");
} else {
io::printf("*");
}
}
io::printf("\n");
}


};

return 0;
}
```

You should get something like this:
```
+********+
**********
+**********+
+***********
************+
+************+
**************
+******+*******+
+******++*******
*******++*******+
+******* *******+
******** ********
+*******+ +*******+
+*******+ ********
******** +*******+
+*******+ +*******+
+*******+ ********
******** +*******+
+*******+ +********
******** ********+
+*******+ +*******+
+*******+ ********+
******** +*******+
+*******+ +********
********+ ********+
+******** +********
+*******+ +********+
******** ********+
+*******+ +********
+*******+ ********+
******** +********
+*******+ +********+
********+ ********+
+******** +********
+***********************************+
*************************************
+*************************************+
**************************************+
+***************************************+
+***************************************+
********+ *********
+******** +********+
+*******+ ********+
+********+ +********+
+******** +********+
********+ *********
+******** +********+
+*******+ +*********
********+ +********+
+******** +********+
********+ *********
+********+ +********+
+******** +*********
********+ +********+
+******** +********+
********+ *********
+********+ +********+
```
Loading