diff options
Diffstat (limited to 'README.md')
-rw-r--r-- | README.md | 120 |
1 files changed, 4 insertions, 116 deletions
@@ -1,118 +1,6 @@ | |||
1 | # Micro Interactive C Framework (MIC) | 1 | # Micro Interactive C Framework (MIC): OpenGL example |
2 | 2 | ||
3 | MIC is a tiny (<300 cloc) framework to boostrap interactive C projects. | 3 | This is an example of using the MIC framework for bootstrapping an OpenGL |
4 | Application code can be dynamically reloaded upon compilation, allowing C to be | 4 | application. For more details head to [the article][article]. |
5 | used as a pseudo-scripting language. This property can be very useful when | ||
6 | developing, but might not be always desirable for a final release, for this | ||
7 | reason, static compilation can be selected as a make target when needed. The | ||
8 | main limitation of hot code reload is that global state can't be stored in the | ||
9 | main app code, but the framework is designed so the state is passed around when | ||
10 | needed and is always accessible for the relevant functions. | ||
11 | 5 | ||
12 | This framework can be easily extended to work with multiple platforms. However, | 6 | [article]: https://badd10de.dev/posts/mic-framework-opengl-example/ |
13 | hot code reload will only be available for platforms that support dynamic | ||
14 | linking. For the moment, only POSIX compliant platforms are supported but | ||
15 | Windows is a target for the near future. | ||
16 | |||
17 | Remember that MIC is only a base, you can (and should) modify anything in here | ||
18 | to adapt it to your particular project. | ||
19 | |||
20 | ## Example usage | ||
21 | |||
22 | Compile and execute the program: | ||
23 | |||
24 | ``` | ||
25 | make && ./build/app | ||
26 | ``` | ||
27 | |||
28 | While the application is running, make changes to the `src/app.c`. For example, | ||
29 | change the `app_step` function from: | ||
30 | |||
31 | ``` | ||
32 | static inline bool | ||
33 | app_step(AppState *state, PlatformAPI platform) { | ||
34 | (void)state; // Unused parameter. | ||
35 | platform.log("STEP"); | ||
36 | platform.sleep(100000); | ||
37 | return true; | ||
38 | } | ||
39 | ``` | ||
40 | |||
41 | To: | ||
42 | |||
43 | ``` | ||
44 | static inline bool | ||
45 | app_step(AppState *state, PlatformAPI platform) { | ||
46 | (void)state; // Unused parameter. | ||
47 | platform.log("Hello world!"); | ||
48 | platform.sleep(100000); | ||
49 | return true; | ||
50 | } | ||
51 | ``` | ||
52 | |||
53 | In another terminal (or using your editor of choice), recompile the program: | ||
54 | |||
55 | ``` | ||
56 | make | ||
57 | ``` | ||
58 | |||
59 | The changes should take effect in the running application. | ||
60 | |||
61 | ## Implementation details | ||
62 | |||
63 | This framework offers two APIs for managing system resources and executing | ||
64 | application logic. The `PlatformAPI` is described in `src/platform.h` and it's | ||
65 | tasked with manage the resources of the platform and/or operating system. For | ||
66 | example, opening/reading files, allocating memory, logging, etc. To support | ||
67 | a new platform it is sufficient to implement the functions described on the API | ||
68 | and make sure to select such platform at compile time. Additionally, the | ||
69 | following internal functions must be implemented for static and dynamic linking: | ||
70 | |||
71 | ``` | ||
72 | // Load the dynamic library and initialize application. Returns the success or | ||
73 | // failure of this operation. | ||
74 | static bool _app_init(AppAPI *api, AppState *state, PlatformAPI platform); | ||
75 | |||
76 | // This function reloads the application code from the dynamic library, | ||
77 | // returning `true` if the AppAPI is ready to be used. | ||
78 | static bool _app_reload(); | ||
79 | |||
80 | // Cleanup resources before exit. | ||
81 | static void _app_destroy(AppAPI *api, AppState *state, PlatformAPI platform); | ||
82 | ``` | ||
83 | |||
84 | The `AppAPI`, described in `src/app.h` and handles app initialization and | ||
85 | destruction, it contains the behaviour in the event of hot code reloading as | ||
86 | well as the main step function. The `init` function typically will be tasked | ||
87 | with initial allocation of resources. The duty of `reload` and `unload` is | ||
88 | application dependent, for example, we might wish to re-compile the shader | ||
89 | programs or reload geometry/sprites when we make modifications to the main | ||
90 | application code. The `step` function is called in every iteration of the loop, | ||
91 | and is where the bulk of the logic will likely be. | ||
92 | |||
93 | The application state is stored in a unique `AppState` structure. MIC has been | ||
94 | architected so that the state and platform functions are available in the | ||
95 | previously mentioned `AppAPI` functions. `AppState` can contain whatever state | ||
96 | is needed and will be persistent when re-compiling. The only limitation is that | ||
97 | if the `AppState` structure changes, the application must be restarted, as the | ||
98 | stored state will become invalid. This can be circumvented by pre-allocating | ||
99 | some memory that can then be partitioned with a pool allocator to suit the | ||
100 | application needs. This design is also conducive for saving state data by simply | ||
101 | serializing the `AppState` structure. | ||
102 | |||
103 | ## Credits | ||
104 | |||
105 | I initially discovered the hot code reloading trick when watching [Casey | ||
106 | Muratori's][casey] [Handmade Hero][handmade] series. It blew my mind! However, | ||
107 | the code he presented was focused solely on Windows and I never end up trying it | ||
108 | myself. Some years later I tried to find a way of making this work in Mac/Linux | ||
109 | when I came across [Chris Wellons'][skeeto] take on this problem with a clever | ||
110 | function pointer API in his [interactive c demo][interac-c-demo] page. This | ||
111 | framework uses a lot of the ideas he presents there, as you can clearly see if | ||
112 | you look at [his code][interac-c-demo]. | ||
113 | |||
114 | [casey]: https://caseymuratori.com | ||
115 | [handmade]: https://handmadehero.org | ||
116 | [skeeto]: https://nullprogram.com | ||
117 | [interac-c-demo]: https://nullprogram.com/blog/2014/12/23/ | ||
118 | [interac-c-demo-github]: https://github.com/skeeto/interactive-c-demo | ||