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