Overview - Build System and the Project Arcitecture
Overview - Build System and the Project Arcitecture
The Build System
- This project is written in C.
- I choose C because it's simple, and you want that when you are trying to do complex things.
- The last thing you want is the language coming in your way.
- Most of the graphics/font libraries are also written in C, so integration becomes easy.
- The build system is CMake
- It "just works" on all the platforms, including Windows
- It has really good IDE support
Project Arcitecture
Project Structure
- The Engine
- The core functionality (like text rendering, windowing, shader code) is implemented in engine.
- The external libraries live in the
external directory.
- The engine does not store any client state, all these modules are just code bundles with a type and a flat API.
- The engine code is neither too generic nor too project specific, that's tricky to pull.
graphics
├── CMakeLists.txt
├── engine
│ ├── assets
│ ├── CMakeLists.txt
│ ├── engine.pc.in
│ ├── include
│ └── source
├── external
│ ├── freetype
│ ├── harfbuzz
│ └── ⋅⋅⋅
└── projects
├── editor
└── game
- The projects build on top of the engine and contribute back the improvements
- The text rendering code in the engine implemented by the editor can later be used in a widget toolkit (let's say).
- The projects manage their own state.
- Some engine subsystems (like windowing) handle user events in callbacks.
- Those callbacks are bridged to the client code using a
struct bridge instance.
The Bridge Interface
1struct bridge {
2 void (*mouse_move)(void *userdata, struct window *window, f64 x, f64 y);
3 void (*mouse_scroll)(void *userdata, struct window *window, f64 x, f64 y);
4 void (*window_resize)(void *userdata, struct window *window, i32 w, i32 h);
5 ...
6};
7
8struct editor_state {
9 struct bridge bridge;
10 struct window *window;
11 struct font *font;
12 .....
13};
- The state type and the bridge interface
- The engine defines
struct bridge, so that's the common known between the engine and the editor
- The editor defines a
struct editor_state type with a struct bridge as the first member.
- Then we pass the bridge to the engine subsystems when initializing them. They store a pointer to it internally.
- Note that this pointer to bridge is also the pointer to our editor state, since it's the first member there.
1/* projects/editor/source/editor.c */
2editor->bridge = (struct bridge) {
3 .mouse_move = mouse_move,
4 .mouse_scroll = mouse_scroll,
5 .window_resize = window_resize,
6};
7
8struct window window_options = {
9 WINDOW_DEFAULTS,
10 .bridge = &editor->bridge,
11};
12
13if (!(rc = window_init(editor->window, window_options))) {
14 goto cleanup;
15}
- The bridge in action
- The windowing subsystem then calls the appropriate callback and passes this bridge pointer to those callbacks.
- In those callbacks on the editor side, we cast these bridge pointers to
struct editor_state *.
- And there we go! The engine doesn't know of the
editor_state and we got the events out nice and tidy.
- We can reuse this in other projects without modifying the engine, or without making them "editor like".
1/* engine/window.c */
2static void __window_mouse_scroll_callback(GLFWwindow *window, f64 x, f64 y) {
3 struct window *_window = glfwGetWindowUserPointer(window);
4 _window->bridge->mouse_scroll(_window->bridge, _window, x, y);
5}
6
7/* projects/editor/source/editor.c */
8void mouse_scroll(void *userdata, struct window *window, f64 x, f64 y) {
9 struct editor_state *editor = userdata;
10 ...
11}
- That's it for now
- The projects are in their really early stages, so there isn't much to talk about them yet.
- The purpose of this post is to get started with the devlog process.
- These are not intuitive things (atleast not for me).
- So with these devlogs, hopefully I can mark the roads I travel, and the milestones I cross.