├── .gitignore
├── README.md
├── color_picker.png
├── debuginator.gif
├── plugins
└── stingray
│ └── the_debuginator_plugin
│ ├── CMakeLists.txt
│ ├── c_api_the_debuginator.cpp
│ ├── c_api_the_debuginator.h
│ ├── copy_latest_debuginator_h.bat
│ ├── resource.h
│ ├── the_debuginator.h
│ ├── the_debuginator_plugin.cpp
│ └── the_debuginator_plugin.rc.in
├── tests
├── 3rdparty
│ ├── SDL_GameControllerDB-master
│ │ ├── .travis.yml
│ │ ├── LICENSE
│ │ ├── README.md
│ │ ├── check.py
│ │ └── gamecontrollerdb.txt
│ ├── Simple-SDL2-Audio
│ │ ├── README.md
│ │ └── src
│ │ │ ├── simple_audio.c
│ │ │ └── simple_audio.h
│ ├── kenney_interfacesounds
│ │ ├── License.txt
│ │ ├── bong_001.wav
│ │ ├── pluck_001.wav
│ │ ├── pluck_002.wav
│ │ └── select_007.wav
│ └── liberation-fonts-ttf-2.00.1
│ │ ├── AUTHORS
│ │ ├── ChangeLog
│ │ ├── LICENSE
│ │ ├── LiberationMono-Bold.ttf
│ │ ├── LiberationMono-BoldItalic.ttf
│ │ ├── LiberationMono-Italic.ttf
│ │ ├── LiberationMono-Regular.ttf
│ │ ├── LiberationSans-Bold.ttf
│ │ ├── LiberationSans-BoldItalic.ttf
│ │ ├── LiberationSans-Italic.ttf
│ │ ├── LiberationSans-Regular.ttf
│ │ ├── LiberationSerif-Bold.ttf
│ │ ├── LiberationSerif-BoldItalic.ttf
│ │ ├── LiberationSerif-Italic.ttf
│ │ ├── LiberationSerif-Regular.ttf
│ │ ├── README
│ │ └── TODO
├── sdl
│ ├── demo.cpp
│ ├── demo.h
│ ├── game.cpp
│ ├── game.h
│ ├── gui.cpp
│ ├── gui.h
│ ├── main.cpp
│ ├── sdl.vcxproj
│ └── sdl.vcxproj.filters
├── sk5.jpg
├── sk5.txt
├── the-debuginator.sln
├── the-debuginator_solution_suppressions.cfg
├── unittest
│ ├── unittest.c
│ ├── unittest.vcxproj
│ └── unittest.vcxproj.filters
└── zig-minimal
│ ├── build.bat
│ └── src
│ ├── build.zig
│ ├── c.zig
│ ├── main.zig
│ ├── the_debuginator_wrapper.c
│ └── the_debuginator_wrapper.h
├── the_debuginator.h
├── the_debuginator_queue.h
└── tools
└── stub_gen.py
/.gitignore:
--------------------------------------------------------------------------------
1 | tests/Build/
2 | *.VC.db
3 | *.VC.VC.opendb
4 | tests/.vs/
5 | tests/zig/src/zig-cache
6 | tests/zig/src/out
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # The Debuginator
2 |
3 | A juicy feature-packed debug menu intended for games.
4 |
5 | It's conceptually based on the debug menu I wrote at Fatshark for **Warhammer: End Times – Vermintide**, where it was - and still is! - used extensively by everyone. Quote by one of the game designers during the Christmas party: *"The debug menu saved man-years for us"*. He was drunk. But not wrong.
6 |
7 | The API is designed to have what I think is just the right amount of responsibilities. The application reads input and uses that to control the menu, and the menu sends back what it wants the application to draw.
8 |
9 | It's nearly feature complete now - unless someone has any cool requests - and as far as I know, bug free.
10 |
11 | I'd really like to add lots of nice GIFs but they get quite large and I'm not keen on forcing people to download megabytes just to view a GitHub project's README. So here's just one with a low resolution and framerate:
12 |
13 |
15 |
16 | There's a fancier demo on Youtube: https://youtu.be/8lA5HQik2wo
17 |
18 | ## Features
19 |
20 | These are subject to change and in various level of implementedness (including currently not at all).
21 |
22 | - :heavy_check_mark: Done.
23 | - :factory: Work in progress
24 | - :small_blue_diamond: Some parts done, other parts on hold.
25 | - :red_circle: Not started.
26 |
27 | ### :heavy_check_mark: STB-style single header library
28 |
29 | Though tests, examples and plugins are in separate files/folders/projects.
30 |
31 | ### :heavy_check_mark: Batteries included
32 |
33 | Think of the_debuginator.h less as a library and more as a *thing* you plug in to get a nice, juicy, feature-packed debug menu.
34 |
35 | Where it makes sense, I've added functionality for extending the menu with your own custom features.
36 |
37 | ### :heavy_check_mark: Politely coded
38 |
39 | It's written in **C99**, to make it easy to add to any project on any platform. In one case I use an anonymous union (I pragma away the warning), so if your compiler doesn't support that, I recommend forking and fixing. I just like the convenience.
40 |
41 | **No globals or static variables**, in case you want to have it in a plugin and reload (or instantiate more than one!).
42 |
43 | **Built using maximum warning levels and warnings as errors**. I use a few #pragmas to ignore warnings I don't think is problematic. Define `DEBUGINATOR_ENABLE_WARNINGS` if you want to handle that manually.
44 |
45 | **Statically analyzed with Cppcheck.** Again, I suppress a few issues that I think aren't problematic. You can check `the-debuginator_solution_suppressions.cfg` if you're interested.
46 |
47 | **It doesn't allocate any memory.** You pass in a buffer at creation and that's what it'll use internally.
48 |
49 | **The library has no dependencies.** It will include some standard headers but only if you don't provide overrides. (For the SDL reference demo, a font is included, and to build you need SDL 2 and SDL TTF.)
50 |
51 | **Multi-platform.** Tested on MSVC 2017/Windows 10 and on the PS4 (so I've been told), and builds on Clang/Linux.
52 |
53 | ### :heavy_check_mark: Scrollable
54 |
55 | Can handle any number of items, the "hot" one will be centered (ish) smoothly.
56 |
57 | Also supports scrolling without changing the hot item, for example using the mouse wheel, touch, or a gamepad stick.
58 |
59 | ### :heavy_check_mark: Performant
60 |
61 | Tested with 10000 menu items with no noticable hit on my laptop running a debug build. That's good enough for me! Hey, it's a debug menu.
62 |
63 | Memory-wise I think you can estimate about 200 bytes, maybe 300, for a typical item in the menu. I've opted to add features, improve speed, and make the code easier to read, at the cost of memory usage. It wouldn't be too hard to optimize it a bit in this regard if you're strained for memory, but it's left as an exercise for the reader.
64 |
65 | Btw, 200 bytes doesn't sound like much, but if you do have 10000 items - perhaps a few for each enemy and item spawned in your level - that means you'll need to spare 2mb of memory, which could potentially be an issue on consoles, phones, Raspberries, and so on. Just bear it in mind.
66 |
67 | ### :heavy_check_mark: Search filter
68 |
69 | Quickly and easily filter the items to find the one you want. Uses a fuzzy search mechanism to allow a user who isn't entirely sure what something is called to find it quickly. Adding a space to the search makes the filter run in "exact" mode; each part of the filter must be matched as-is.
70 |
71 | Check my post on this for a bit of details about it: https://medium.com/@Srekel/implementing-a-fuzzy-search-algorithm-for-the-debuginator-cacc349e6c55
72 |
73 | ### :heavy_check_mark: Save/Load of settings
74 |
75 | So you start up with the settings you had when you exited. Simple interface, application needs to handle the actual I/O.
76 |
77 | ### :heavy_check_mark: Dynamic add and remove of items
78 |
79 | So you could, for example, have items that are only available when you are in the game's main menu, or have one item for each currently spawned enemy in the game.
80 |
81 | ### :heavy_check_mark: Left or right aligned
82 |
83 | Because some games already have other important stuff on the left side of the screen.
84 |
85 | Hey, you could even have one instance of The Debuginator on the left and another on the right.
86 |
87 | ### :heavy_check_mark: Hierarchical
88 |
89 | Put things in folders in folders in folders. They can be expanded and collapsed.
90 |
91 | Folder states are persisted automatically if you implement the save interface.
92 | This is useful when you have a lot of items but different users are only interested in different subsets of them.
93 |
94 | ### :heavy_check_mark: Custom item editors
95 |
96 | Different editors for different types of items, and support for users adding their own.
97 |
98 | ### :heavy_check_mark: Input
99 |
100 | The API for manouvering the menu is agnostic regarding keyboard/gamepad. It's handled at application layer, though guidelines for how to bind keys exist - see the demo.
101 |
102 | Also supports mouse and touch input.
103 |
104 | ### :heavy_check_mark: Presets
105 |
106 | Activate one item to activate a number of other ones. Useful for if a user tends to reset her debug settings but has a lot of them she often wants to enable. Or if your QA should play under certain circumstances. Or if you have a few settings that is just really nice to always have enabled, for new devs.
107 |
108 | ### :heavy_check_mark: Hotkeys
109 |
110 | Press a key when debug menu is active to assign the current item/value. Press it again when the menu is closed to toggle/set the value.
111 |
112 | Hot keys are persisted automatically if you implement the save interface.
113 |
114 | ### :heavy_check_mark: Default values
115 |
116 | Different colors for when the current value of an item is different from it's defined *default value* makes it clearer to the developer that she is or isn't working under the game's standard conditions.
117 |
118 | ### :heavy_check_mark: Unit tests
119 |
120 | I used these extensively in the beginning of the project but the fun and usefulness of keeping them up to date is gone. They are surpassed by the SDL reference demo. I'm conflicted as whether to mark it as a done feature but yeah, for all intents and purposes, they are done.
121 |
122 | ### :heavy_check_mark: Nice look & feel
123 |
124 | Nice default color scheme, multiple themes to choose from, unique "editors" for different types of data, smooth animations, juicy feedback.
125 |
126 | Yes, it's important.
127 |
128 | ### :heavy_check_mark: Reference implementation
129 |
130 | Written in near-C C++ and SDL.
131 |
132 | There's also a plugin for Autodesk Stingray. Since Stingray is basically dead I'm not likely to work further on the plugin, but it's useful as another reference implementation.
133 |
134 | ### :factory: Thread safe
135 |
136 | Not really - I don't want to add multithreading constructs to the_debuginator - it's up to the application to ensure that no thread writes or reads to it while another thread is writing. While I don't intend to change that, I **am** working on a way to make it easier to use in a multithreaded environment (that's how our own game at Warpzone Studios is engineered) but it's not done yet.
137 |
138 | ### :red_circle: Accordiony
139 |
140 | The idea is that, no matter how far down or deep you scroll, you can always see the folders above the current item.
141 |
142 | ### :red_circle: Favorites
143 |
144 | Set your most used ones. They will show up in a special folder near the top.
145 |
146 | ## Can I help?
147 |
148 | Sure. Any helpful comments, bug reports, or PRs appreciated.
149 |
150 | Even though I think The Debuginator has most of the features I envision for it, have probably missed something, so I would love feature requests!
151 |
152 | ## License
153 |
154 | Similarly to STB's single header libraries: The Debuginator and other source files in this repository are in the public domain. You can do anything you want with them. You have no legal obligation to do anything else, although I appreciate attribution.
155 |
156 | They are also licensed under the MIT open source license, if you have lawyers who are unhappy with public domain. Every source file includes an explicit dual-license for you to choose from.
157 |
158 | Note that this does **NOT** include any folders that has LICENSE or README files that specifies their own license. They retain their own licenses.
159 |
160 | # How to use the_debuginator.h
161 |
162 | I really recommend looking at the SDL demo for a real use case on how to set it up and use The Debuginator. It also includes basic save/load which is something you *really* want for your debug menu! :)
163 |
164 | ## Installation
165 | Put the_debuginator.h somewhere in your project. It's an STB-style single header library and as such usage is a bit special.
166 |
167 | Add this to *one* cpp file:
168 |
169 | ```C
170 | #define DEBUGINATOR_IMPLEMENTATION
171 | // #define DEBUGINATOR_OPTIONAL_SETTING_OR_OVERRIDE_X
172 | // #define DEBUGINATOR_OPTIONAL_SETTING_OR_OVERRIDE_Y
173 | // #define DEBUGINATOR_OPTIONAL_SETTING_OR_OVERRIDE_ETC
174 | #include "path/to/the_debuginator.h"
175 | ```
176 |
177 | ## Setup
178 |
179 | In the same cpp file:
180 |
181 | ```C
182 | // Set up debuginator callbacks
183 | void draw_text(const char* text, DebuginatorVector2* position, DebuginatorColor* color, DebuginatorFont* font, void* userdata) {
184 | // Your code goes here
185 | }
186 |
187 | void draw_rect(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorColor* color, void* userdata) {
188 | // Your code goes here
189 | }
190 |
191 | void word_wrap(const char* text, DebuginatorFont font, float max_width, unsigned* row_count, unsigned* row_lengths, int row_lengths_buffer_size, void* app_userdata) {
192 | // Your code goes here
193 | }
194 |
195 | void word_wrap2(const char* text, DebuginatorFont font, float max_width, char** buffer, int buffer_size, void* userdata) {
196 | // Your code goes here
197 | }
198 |
199 | DebuginatorVector2 text_size(const char* text, DebuginatorFont* font, void* userdata) {
200 | // Your code goes here
201 | }
202 |
203 | int main(...) {
204 | TheDebuginatorConfig config;
205 | debuginator_get_default_config(&config);
206 |
207 | config.memory_arena_capacity = 1024 * 512;
208 | config.memory_arena = (char*)malloc(config.memory_arena_capacity);
209 |
210 | config.draw_rect = draw_rect;
211 | config.draw_text = draw_text;
212 | config.word_wrap = word_wrap;
213 | config.text_size = text_size;
214 |
215 | config.size.x = 500;
216 | config.size.y = GetMyScreenResolution().y; // You need to calculate this.
217 |
218 | config.screen_resolution.x = config.size.x;
219 | config.screen_resolution.y = config.size.y;
220 |
221 | // There's a bunch of other things you CAN change in the config, but these things
222 | // are the necessary stuff.
223 |
224 | config.create_default_debuginator_items = true; // I recommend this
225 |
226 | TheDebuginator debuginator;
227 | debuginator_create(&config, &debuginator);
228 |
229 | // debuginator is now the thing that you pass into the API functions to update/change/draw The Debuginator.
230 | }
231 | ```
232 |
233 | Actual usage, such as adding items or modifying settings, can be done from any C or C++ file.
234 |
235 | ## How to use
236 |
237 | ### The gist of it
238 | This is the core for creating an item:
239 |
240 | ```C
241 | DebuginatorItem* debuginator_create_array_item(TheDebuginator* debuginator,
242 | DebuginatorItem* parent, const char* path, const char* description,
243 | DebuginatorOnItemChangedCallback on_item_changed_callback, void* user_data,
244 | const char** value_titles, void* values, int num_values, int value_size)
245 | ```
246 |
247 | Don't be alarmed - there are utility functions that make it easier to use! :) See below.
248 |
249 | Each *item* is defined by its path. If you create two items with the same path, only one will actually exist - with the data from the last call.
250 |
251 | An *leaf item* has a list of *values*. A value has a title and a... value. The Debuginator doesn't care about what the values are, it just sees them as an array; a pointer and an element size. When you activate a value on an item, you'll get a callback with the value pointing to the correct place in that array. For bools, you don't really need to care about that stuff, it's handled by the wrapper function.
252 |
253 | The leaf item also has a userdata field that you will use in your callbacks.
254 |
255 | In addition to leaf items, there are folder items which currently doesn't really do anything in particular except be there. You don't need to create folder items before items, they'll be created implicitly if they don't already exist. You can pass NULL to the *parent* parameter, in fact, it's the most common use case. It's mainly there as an optimization.
256 |
257 | ### Saving and loading
258 |
259 | I recommend looking at the SDL demo for a good example of how to do this. But here's how it works.
260 |
261 | Saving is fairly straightforward. Call debuginator_save and pass in a callback that gets called for each item who's value is different from the default. I recommend storing it to a single key-value map, like "MyGame/MySetting = True".
262 |
263 | Folders will also save their state if they are collapsed. This is so that they remain collapsed if you for example close the game down and open it up again.
264 |
265 | ### Examples
266 |
267 | Here's how to add a boolean item that toggles god mode for the player:
268 |
269 | ```C
270 | struct Player {
271 | int health;
272 | bool godmode;
273 | }
274 |
275 | Player my_player;
276 | my_player.health = 100;
277 | my_player.godmode = false;
278 |
279 | debuginator_create_bool_item(
280 | &debuginator,
281 | "Player Mechanics/God Mode",
282 | "Player is invincible if enabled",
283 | &my_player.godmode);
284 | ```
285 |
286 | Here's how to create a preset item - it'll toggle multiple things.
287 |
288 | ```C
289 | const char* preset_paths[2] = { "Workflow/Skip intro", "Player Mechanics/God Mode" };
290 | const char* preset_value_titles[2] = { "True", "True" };
291 | debuginator_create_preset_item(&debuginator,
292 | "My Presets/Good workflow",
293 | preset_paths, preset_value_titles, NULL, 2);
294 | ```
295 |
296 | Here's how to create a generic item with a few strings and no callback (not sure what use case there is for that, but hey)... If you look at the definition of the other create_item functions, you'll see that they simply wrap this one.
297 |
298 | ```C
299 | {
300 | static const char* string_titles[5] = { "String A", "String B", "String C", "String D", "String E" };
301 | debuginator_create_array_item(&debuginator,
302 | NULL, "My Game/String Test",
303 | "Multiple strings.", NULL, NULL,
304 | string_titles, NULL, 5, 0);
305 | }
306 | ```
307 |
308 | Here's how to create a generic item with multiple things WITH a callback.
309 |
310 | ```C
311 | void on_change_ui_size(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
312 | (void)value_title;
313 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
314 | int size_category = *(int*)value;
315 | if (size_category == 0) {
316 | set_ui_size(&wrapper->debuginator, 14, 22);
317 | }
318 | else if (size_category == 1) {
319 | set_ui_size(&wrapper->debuginator, 20, 30);
320 | }
321 | else if (size_category == 2) {
322 | set_ui_size(&wrapper->debuginator, 32, 40);
323 | }
324 | else if (size_category == 3) {
325 | set_ui_size(&wrapper->debuginator, 64, 70);
326 | }
327 | }
328 |
329 | // Later...
330 |
331 | static const char* uisize_titles[4] = { "Small", "Medium", "Large", "ULTRA LARGE" };
332 | static int uisizes[4] = { 0, 1, 2, 3 };
333 | DebuginatorItem* uisize_item = debuginator_create_array_item(debuginator,
334 | NULL, "Debuginator/UI size",
335 | "Change font and item size.", on_change_ui_size, wrapper,
336 | uisize_titles, uisizes, 4, sizeof(uisizes[0]));
337 | ```
338 |
339 | ## A note on memory
340 |
341 | The Debuginator uses (what I call) a block allocator. It's slightly wasteful in terms of memory but should be pretty efficient for allocating and deallocating.
342 |
343 | You provide a buffer for The Debuginator to use, and it'll use that. When there's no more memory.. it'll probably crash or something.
344 |
345 | If you want to give The Debuginator a string for it to own (and deallocate), you can do that. Look at:
346 | ```C
347 | char* debuginator_copy_string(TheDebuginator* debuginator, const char* string, int length);
348 | ```
349 |
350 | ## API
351 |
352 | You know, it's best to just look in the header file and see which functions are exposed, but... here's the API such as it is currently. There's additional information in the code.
353 |
354 | ```C
355 | bool debuginator_is_open(TheDebuginator* debuginator);
356 | void debuginator_set_open(TheDebuginator* debuginator, bool open);
357 |
358 | DebuginatorItem* debuginator_create_array_item(TheDebuginator* debuginator,
359 | DebuginatorItem* parent, const char* path, const char* description,
360 | DebuginatorOnItemChangedCallback on_item_changed_callback, void* user_data,
361 | const char** value_titles, void* values, int num_values, int value_size);
362 |
363 | DebuginatorItem* debuginator_create_bool_item(TheDebuginator* debuginator, const char* path, const char* description, void* user_data);
364 | DebuginatorItem* debuginator_create_preset_item(TheDebuginator* debuginator, const char* path, const char** paths, const char** value_titles, int** value_indices, int num_paths);
365 |
366 | DebuginatorItem* debuginator_create_folder_item(TheDebuginator* debuginator, DebuginatorItem* parent, const char* title, int title_length);
367 | DebuginatorItem* debuginator_get_item(TheDebuginator* debuginator, DebuginatorItem* parent, const char* path, bool create_if_not_exist);
368 | void debuginator_set_hot_item(TheDebuginator* debuginator, const char* path);
369 | DebuginatorItem* debuginator_get_hot_item(TheDebuginator* debuginator);
370 | void debuginator_remove_item(TheDebuginator* debuginator, DebuginatorItem* item);
371 | void debuginator_remove_item_by_path(TheDebuginator* debuginator, const char* path);
372 |
373 | int debuginator_save(TheDebuginator* debuginator, DebuginatorSaveItemCallback callback, char* save_buffer, int save_buffer_size);
374 | void debuginator_load_item(TheDebuginator* debuginator, const char* path, const char* value_title);
375 | void debuginator_set_default_value(TheDebuginator* debuginator, const char* path, const char* value_title, int value_index); // value index is used if value_title == NULL
376 | void debuginator_set_edit_type(TheDebuginator* debuginator, const char* path, DebuginatorItemEditorDataType edit_type);
377 |
378 | void debuginator_activate(TheDebuginator* debuginator, DebuginatorItem* item);
379 |
380 | void debuginator_move_to_next_leaf(TheDebuginator* debuginator, bool long_move);
381 | void debuginator_move_to_prev_leaf(TheDebuginator* debuginator, bool long_move);
382 | void debuginator_move_to_child(TheDebuginator* debuginator, bool toggle_and_activate);
383 | void debuginator_move_to_parent(TheDebuginator* debuginator);
384 |
385 | bool debuginator_is_filtering_enabled(TheDebuginator* debuginator);
386 | void debuginator_set_filtering_enabled(TheDebuginator* debuginator, bool enabled);
387 | char* debuginator_get_filter(TheDebuginator* debuginator);
388 | void debuginator_update_filter(TheDebuginator* debuginator, const char* wanted_filter);
389 |
390 | void debuginator_set_item_height(TheDebuginator* debuginator, int item_height);
391 | void debuginator_set_size(TheDebuginator* debuginator, int width, int height);
392 |
393 | ```
394 |
395 | # How to run the Unit Test
396 |
397 | Open the Visual Studio solution. Build it. Set the *unittest* project as the StartUp project. Run.
398 |
399 | Note: The SDL demo project won't build until you fix the dependencies so you might want to unload it.
400 | Note: The unit tests haven't been updated in a long while so you probably don't want to do this.
401 |
402 | # How to run the SDL demo
403 |
404 | Open the Visual Studio solution. Build it. Set the *sdl* project as the StartUp project. Run.
405 |
406 | You'll need dependencies to build it. Get SDL 2 and SDLTTF 2. I'll update this with better instructions at some point. :)
407 |
408 | # How to use Stingray Plugin
409 |
410 | Not supported anymore (I mean, technically it should work with little problems but Stingray isn't available to the public any more so you are almost certainly not using it).
411 |
--------------------------------------------------------------------------------
/color_picker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/color_picker.png
--------------------------------------------------------------------------------
/debuginator.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/debuginator.gif
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.6)
2 | project(the_debuginator_plugin)
3 |
4 | # Include common plugin CMake scripts and set the type of plugin to be to and ENGINE_PLUGIN
5 | # set(ENGINE_PLUGIN ON)
6 | # set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${REPOSITORY_DIR}/cmake")
7 | # include(CMakePlugin)
8 |
9 | # Scan and add project source files
10 | find_source_files(ALL_SOURCE_FILES)
11 |
12 | # Add windows version resource if windows dll
13 | if( PLATFORM_WINDOWS )
14 | if( BUILD_SHARED_LIBS )
15 | include_directories(${PROJECT_SOURCE_DIR})
16 | configure_file("${PROJECT_SOURCE_DIR}/${PROJECT_NAME}.rc.in" "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.rc")
17 | set(RESOURCE_FILES "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.rc")
18 | source_group("Resources" FILES ${RESOURCE_FILES})
19 | list(APPEND ALL_SOURCE_FILES ${RESOURCE_FILES})
20 | endif()
21 | endif()
22 |
23 | # Define automatic namespace for C++
24 | add_compile_options(-DPLUGIN_NAMESPACE=${PROJECT_NAME})
25 |
26 | # Include editor plugin sdk files
27 | include_directories(${REPOSITORY_DIR}/stingray_sdk)
28 | include_directories(${REPOSITORY_DIR}/runtime/sdk)
29 |
30 | # Create target and set compile/link options
31 | add_library(${PROJECT_NAME} ${ALL_SOURCE_FILES})
32 |
33 | # Set target properties
34 | set_system_properties(${PROJECT_NAME})
35 | set_target_properties(${PROJECT_NAME} PROPERTIES FOLDER "${ENGINE_PLUGINS_FOLDER_NAME}")
36 | set(TARGET_BASE_NAME "${PROJECT_NAME}_${ENGINE_PLUGIN_SUFFIX}_$>")
37 | set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME "${TARGET_BASE_NAME}")
38 | if( BUILD_SHARED_LIBS AND PLATFORM_IOS )
39 | set_target_properties(${PROJECT_NAME} PROPERTIES XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY "${ENGINE_IOS_CODE_SIGN_IDENTITY}")
40 | endif()
41 |
42 |
43 | # Set engine runtime plugin properties and enable hot-reloading.
44 | set_plugin_runtime_output_directory("${TARGET_BASE_NAME}" "${ENGINE_PLUGINS_INSTALL_DIR}")
45 |
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/c_api_the_debuginator.cpp:
--------------------------------------------------------------------------------
1 |
2 | // Include Debuginator, override any appropriate functions
3 | #include
4 | #define DEBUGINATOR_IMPLEMENTATION
5 | #define DEBUGINATOR_assert XENSURE
6 | #include "the_debuginator.h"
7 |
8 | #include
9 | #include "c_api_the_debuginator.h"
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | struct TheDebuginatorWrapper {
17 | TheDebuginator debuginator;
18 | char id[64];
19 | ConstWindowPtr window;
20 | GuiPtr gui;
21 | uint64_t font;
22 | MaterialPtr font_material;
23 | bool memory_owned_by_this_plugin;
24 | int font_size;
25 | bool axis_selected_repeat;
26 | bool axis_scroll_repeat;
27 | float scroll_repeat_timer;
28 | };
29 |
30 | struct InputWrapper {
31 | InputControllerCApi* api;
32 | CApiInputControllerPtr controller;
33 |
34 | float time_since_pressed;
35 |
36 | // TODO: Pre-calc hashes.
37 | bool button(const char* button) {
38 | using namespace stingray_plugin_foundation;
39 | return api->button(controller, api->button_id(controller, hash32(button))) > 0;
40 | }
41 |
42 | bool pressed(const char* button) {
43 | using namespace stingray_plugin_foundation;
44 | return api->pressed(controller, api->button_id(controller, hash32(button))) > 0;
45 | }
46 |
47 | bool pressed_repeat(const char* button) {
48 | using namespace stingray_plugin_foundation;
49 | bool pressed = api->button(controller, api->button_id(controller, hash32(button))) > 0;
50 |
51 | // Faux repeat support.
52 | if (pressed) {
53 | if (time_since_pressed == -1) {
54 | time_since_pressed = 0;
55 | return true;
56 | }
57 | else if (time_since_pressed > 0.3f) {
58 | time_since_pressed = 0.25f;
59 | return true;
60 | }
61 | return false;
62 | }
63 |
64 | return false;
65 | }
66 |
67 | CApiVector3 axis(const char *axis) {
68 | using namespace stingray_plugin_foundation;
69 | return api->axis(controller, api->axis_id(controller, hash32(axis)), 0);
70 | }
71 | };
72 |
73 | struct PluginMemory {
74 | AllocatorObject* allocator_object;
75 | TheDebuginatorWrapper debuginators[8];
76 | int num_debuginators = 0;
77 | InputWrapper input_wrapper;
78 | };
79 |
80 | static PluginMemory* plugin_memory = nullptr;
81 |
82 | // Engine APIs
83 | static AllocatorApi* allocator_api = nullptr;
84 | static ScriptApi* script_api = nullptr;
85 |
86 | void set_ui_size(TheDebuginator* debuginator, int font_size, int item_height);
87 |
88 | namespace {
89 | void draw_text(const char* text, DebuginatorVector2* position, DebuginatorColor* color, DebuginatorFont* font, void* app_userdata) {
90 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
91 | CApiVector2 gui_position = { position->x, position->y };
92 | CApiVector4 gui_color = { (float)color->a, (float)color->r, (float)color->g, (float)color->b };
93 | gui_position.y = wrapper->debuginator.screen_resolution.y - position->y - wrapper->font_size * 0.75;
94 | script_api->Gui->text(wrapper->gui, text, wrapper->font, wrapper->font_size, wrapper->font_material, &gui_position, 100 + 1, 0, &gui_color);
95 | }
96 |
97 | void draw_rect(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorColor* color, void* app_userdata) {
98 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
99 | CApiVector2 gui_position = { position->x, position->y };
100 | CApiVector4 gui_color = { (float)color->a, (float)color->r, (float)color->g, (float)color->b };
101 | gui_position.y = wrapper->debuginator.screen_resolution.y - position->y - size->y;
102 | script_api->Gui->rect(wrapper->gui, &gui_position, 100, (ConstVector2Ptr)size, &gui_color);
103 | }
104 |
105 | void word_wrap(const char* text, DebuginatorFont font, float max_width, unsigned* row_count, unsigned* row_lengths, unsigned row_lengths_buffer_size, void* app_userdata) {
106 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
107 | *row_count = script_api->Gui->word_wrap(wrapper->gui, text, wrapper->font, wrapper->font_size, max_width, " ", "-+&/", "\n", 0, row_lengths, row_lengths_buffer_size);
108 | }
109 |
110 | DebuginatorVector2 text_size(const char* text, DebuginatorFont* font, void* app_userdata) {
111 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
112 | TextExtentsResult results = script_api->Gui->text_extents(wrapper->gui, text, wrapper->font, wrapper->font_size, 0);
113 | CApiVector2 text_size = { results.max.x - results.min.x, results.max.y - results.min.y };
114 | //text_size.x *= 2; // WHYYYY
115 | text_size.y *= 2;
116 | return *(DebuginatorVector2*)&text_size;
117 | }
118 |
119 | // Item callbacks
120 | void on_change_ui_size(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
121 | (void)value_title;
122 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)app_userdata;
123 | int size_category = *(int*)value;
124 | if (size_category == 0) {
125 | set_ui_size(&wrapper->debuginator, 14, 22);
126 | }
127 | else if (size_category == 1) {
128 | set_ui_size(&wrapper->debuginator, 20, 30);
129 | }
130 | else if (size_category == 2) {
131 | set_ui_size(&wrapper->debuginator, 32, 40);
132 | }
133 | else if (size_category == 3) {
134 | set_ui_size(&wrapper->debuginator, 64, 70);
135 | }
136 | }
137 | }
138 |
139 | void setup_api(GetApiFunction get_engine_api, const char* plugin_name) {
140 | allocator_api = (AllocatorApi*)get_engine_api(ALLOCATOR_API_ID);
141 | script_api = (ScriptApi*)get_engine_api(C_API_ID);
142 |
143 | if (plugin_memory == nullptr) {
144 | AllocatorObject* allocator_object = allocator_api->make_plugin_allocator(plugin_name);
145 | plugin_memory = (PluginMemory*)allocator_api->allocate(allocator_object, sizeof(PluginMemory), 16);
146 | memset(plugin_memory, 0, sizeof(*plugin_memory));
147 | plugin_memory->allocator_object = allocator_object;
148 | plugin_memory->input_wrapper.time_since_pressed = -1;
149 | }
150 | }
151 |
152 | void shutdown_api() {
153 | if (plugin_memory != nullptr) {
154 | for (int i = 0; i < plugin_memory->num_debuginators; i++) {
155 | TheDebuginatorWrapper* wrapper = &plugin_memory->debuginators[i];
156 | if (wrapper->memory_owned_by_this_plugin) {
157 | allocator_api->deallocate(plugin_memory->allocator_object, wrapper->debuginator.memory_arena);
158 | }
159 | }
160 |
161 | AllocatorObject* allocator_object = plugin_memory->allocator_object;
162 | allocator_api->deallocate(plugin_memory->allocator_object, plugin_memory);
163 | allocator_api->destroy_plugin_allocator(allocator_object);
164 | plugin_memory = nullptr;
165 | }
166 | }
167 |
168 | void* start_reload(GetApiFunction get_engine_api) {
169 | return plugin_memory;
170 | }
171 |
172 | void finish_reload(GetApiFunction get_engine_api, void *state) {
173 | plugin_memory = (PluginMemory*)state;
174 | }
175 |
176 | void update_debuginators(float dt) {
177 | for (int i = 0; i < plugin_memory->num_debuginators; i++) {
178 | TheDebuginatorWrapper* wrapper = &plugin_memory->debuginators[i];
179 |
180 | CApiVector2 resolution = script_api->Gui->resolution(NULL, wrapper->window);
181 | wrapper->debuginator.size.y = resolution.y;
182 | wrapper->debuginator.screen_resolution.y = resolution.y;
183 |
184 | debuginator_update(&wrapper->debuginator, dt);
185 | debuginator_draw(&wrapper->debuginator, dt);
186 | }
187 |
188 | if (plugin_memory->input_wrapper.time_since_pressed != -1) {
189 | plugin_memory->input_wrapper.time_since_pressed += dt;
190 | }
191 | }
192 |
193 | void destroy_debuginator(TheDebuginator* debuginator);
194 | TheDebuginator* get_debuginator(const char* id);
195 |
196 | TheDebuginator* create_debuginator(const char* id, DebuginatorPluginCreateContext* context) {
197 | if (id == NULL) {
198 | id = "default";
199 | }
200 |
201 | XASSERT(plugin_memory->num_debuginators < 8, "Too many debuginators created. Good lord, how many do you need?!");
202 | XASSERT(get_debuginator(id) == NULL, "Debuginator with that name already exists.");
203 |
204 | TheDebuginatorWrapper* wrapper = &plugin_memory->debuginators[plugin_memory->num_debuginators];
205 | memset(wrapper, 0, sizeof(TheDebuginatorWrapper));
206 | strcpy_s(wrapper->id, sizeof(plugin_memory->debuginators[plugin_memory->num_debuginators].id), id);
207 |
208 | wrapper->window = context->window;
209 | wrapper->font = context->font;
210 | wrapper->font_material = context->font_material;
211 | wrapper->gui = context->gui;
212 | wrapper->font_size = context->font_size > 0 ? context->font_size : 20;
213 |
214 | if (context->config.draw_text == NULL) {
215 | XASSERT(wrapper->font, "No font defined");
216 | XASSERT(wrapper->font_material, "No font_material defined");
217 | XASSERT(wrapper->gui, "No gui defined");
218 | context->config.draw_text = draw_text;
219 | context->config.draw_rect = draw_rect;
220 | context->config.word_wrap = word_wrap;
221 | context->config.text_size = text_size;
222 | context->config.app_user_data = wrapper;;
223 | }
224 |
225 | if (context->config.memory_arena == NULL) {
226 | wrapper->memory_owned_by_this_plugin = true;
227 | XASSERT(context->config.memory_arena_capacity != 0, "You must provide a wanted memory size.");
228 | context->config.memory_arena = (char*)allocator_api->allocate(plugin_memory->allocator_object, context->config.memory_arena_capacity, 16);
229 | }
230 |
231 | context->config.screen_resolution.x = script_api->Gui->resolution(NULL, wrapper->window).x;
232 | context->config.screen_resolution.y = script_api->Gui->resolution(NULL, wrapper->window).y;
233 | context->config.size.y = context->config.screen_resolution.y;
234 |
235 | TheDebuginator* debuginator = &wrapper->debuginator;
236 | debuginator_create(&context->config, debuginator);
237 |
238 | {
239 | static const char* uisize_titles[4] = { "Small", "Medium", "Large", "ULTRA LARGE" };
240 | static int uisize_indices[4] = { 0, 1, 2, 3 };
241 | DebuginatorItem* uisize_item = debuginator_create_array_item(debuginator, NULL, "Debuginator/UI size",
242 | "Change font and item size.", on_change_ui_size, wrapper,
243 | uisize_titles, uisize_indices, 4, sizeof(uisize_indices[0]));
244 |
245 | uisize_item->leaf.default_index = 1;
246 | uisize_item->leaf.hot_index = 1;
247 | uisize_item->leaf.active_index = 1;
248 | debuginator_activate(debuginator, uisize_item, false);
249 | }
250 |
251 | plugin_memory->num_debuginators++;
252 | return debuginator;
253 | }
254 |
255 | void destroy_debuginator(TheDebuginator* debuginator) {
256 | if (debuginator == NULL) {
257 | debuginator = get_debuginator("default");
258 | }
259 |
260 | for (int i = 0; i < plugin_memory->num_debuginators; i++) {
261 | if (debuginator == &plugin_memory->debuginators[i].debuginator) {
262 | TheDebuginatorWrapper* wrapper = &plugin_memory->debuginators[i];
263 | if (wrapper->memory_owned_by_this_plugin) {
264 | allocator_api->deallocate(plugin_memory->allocator_object, debuginator->memory_arena);
265 | }
266 |
267 | plugin_memory->debuginators[i] = plugin_memory->debuginators[--plugin_memory->num_debuginators];
268 | break;
269 | }
270 | }
271 | }
272 |
273 | TheDebuginator* get_debuginator(const char* id) {
274 | if (id == NULL) {
275 | id = "default";
276 | }
277 |
278 | for (int i = 0; i < plugin_memory->num_debuginators; i++) {
279 | if (strcmp(id, plugin_memory->debuginators[i].id) == 0) {
280 | return &plugin_memory->debuginators[i].debuginator;
281 | }
282 | }
283 |
284 | return NULL;
285 | }
286 |
287 | void handle_default_input(TheDebuginator* debuginator, unsigned devices) {
288 | if (debuginator == NULL) {
289 | debuginator = get_debuginator("default");
290 | }
291 |
292 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)debuginator;
293 |
294 | InputControllerCApi* api = script_api->Input->InputController;
295 | InputWrapper& input_wrapper = plugin_memory->input_wrapper;
296 | input_wrapper.api = api;
297 |
298 | if (!script_api->Window->has_focus(wrapper->window)) {
299 | input_wrapper.time_since_pressed = -1;
300 | return;
301 | }
302 |
303 | while (devices & Debuginator_Keyboard) { // So we can break out of the scope
304 | devices &= ~Debuginator_Keyboard;
305 | CApiInputControllerPtr keyboard = script_api->Input->keyboard();
306 | input_wrapper.controller = keyboard;
307 |
308 | if (api->any_released(input_wrapper.controller) != UINT_MAX) {
309 | input_wrapper.time_since_pressed = -1;
310 | }
311 |
312 | if (!debuginator_is_open(debuginator)) {
313 | if (input_wrapper.pressed("right")) {
314 | debuginator_set_open(debuginator, true);
315 | }
316 |
317 | break;
318 | }
319 |
320 | bool ctrl_pressed = input_wrapper.button("left ctrl") ||
321 | input_wrapper.button("right ctrl");
322 |
323 | if (input_wrapper.pressed_repeat("up")) {
324 | bool long_move = ctrl_pressed;
325 | debuginator_move_to_prev_leaf(debuginator, long_move);
326 | }
327 | else if (input_wrapper.pressed_repeat("down")) {
328 | bool long_move = ctrl_pressed;
329 | debuginator_move_to_next_leaf(debuginator, long_move);
330 | }
331 | else if (input_wrapper.pressed_repeat("home")) {
332 | debuginator_move_to_root(debuginator);
333 | debuginator->focus_height = default_focus_height;
334 | }
335 | else if (input_wrapper.pressed_repeat("end")) {
336 | debuginator_move_to_root(debuginator);
337 | debuginator_move_sibling_previous(debuginator);
338 | debuginator->focus_height = default_focus_height;
339 | }
340 | else if (input_wrapper.pressed("left")) {
341 | DebuginatorItem* hot_item = debuginator_get_hot_item(debuginator);
342 | if (debuginator_is_open(debuginator) && (hot_item->is_folder || (!hot_item->is_folder && hot_item->leaf.is_expanded))) {
343 | debuginator_move_to_parent(debuginator);
344 | }
345 | }
346 | else if (input_wrapper.pressed("escape") || input_wrapper.pressed("delete")) {
347 | debuginator_set_open(debuginator, false);
348 | }
349 | else if (input_wrapper.pressed("enter")) {
350 | debuginator_move_to_child(debuginator, false);
351 | }
352 |
353 | if (input_wrapper.pressed_repeat("backspace")) {
354 | const char* filter = debuginator_get_filter(debuginator);
355 | int filter_length = (int)strlen(filter);
356 |
357 | if (filter_length > 0) {
358 | char new_filter[64] = { 0 };
359 | memcpy(new_filter, filter, filter_length);
360 | const char* filter = debuginator_get_filter(debuginator);
361 | int filter_length = (int)strlen(filter);
362 | if (filter_length > 0) {
363 | new_filter[--filter_length] = '\0';
364 | }
365 | debuginator_update_filter(debuginator, new_filter);
366 | }
367 | else if (debuginator_is_filtering_enabled(debuginator)) {
368 | debuginator_set_filtering_enabled(debuginator, false);
369 | }
370 | }
371 |
372 | if (ctrl_pressed && input_wrapper.pressed_repeat("w")) {
373 | debuginator_update_filter(debuginator, "");
374 | } else {
375 | unsigned int num_key_strokes;
376 | const int* keystrokes = script_api->Input->Keyboard->keystrokes(keyboard, &num_key_strokes);
377 | if (num_key_strokes > 0) {
378 | const char* filter = debuginator_get_filter(debuginator);
379 | int filter_length = (int)strlen(filter);
380 | if (filter_length + (int)num_key_strokes < wrapper->font_size) {
381 | char new_filter[64] = { 0 };
382 | memcpy(new_filter, filter, filter_length);
383 | int real_strokes = 0;
384 | for (unsigned int i = 0; i < num_key_strokes; ++i) {
385 | if (32 <= keystrokes[i] && keystrokes[i] <= 125) {
386 | new_filter[filter_length++] = (char)keystrokes[i];
387 | ++real_strokes;
388 | }
389 | }
390 |
391 | if (real_strokes > 0) {
392 | if (!debuginator_is_filtering_enabled(debuginator)) {
393 | debuginator_set_filtering_enabled(debuginator, true);
394 | }
395 | debuginator_update_filter(debuginator, new_filter);
396 | // Update focus height to match new hot item
397 | float max_height = debuginator_total_height(debuginator);
398 | int active_height = 0;
399 | debuginator__distance_to_hot_item(debuginator->root, debuginator->hot_item, debuginator->item_height, &active_height);
400 | float height_pixels = debuginator->focus_height * debuginator->size.y - active_height;
401 | if (height_pixels < -(max_height - (1.f - default_focus_height) * debuginator->size.y)) {
402 | debuginator->focus_height = -(max_height - (1.f - default_focus_height) * debuginator->size.y - active_height) / debuginator->size.y;
403 | } else if (height_pixels > default_focus_height * debuginator->size.y) {
404 | debuginator->focus_height = (default_focus_height * debuginator->size.y + active_height) / debuginator->size.y;
405 | }
406 | }
407 | }
408 | }
409 | }
410 | }
411 |
412 | if (devices & Debuginator_Mouse) {
413 | CApiInputControllerPtr mouse = script_api->Input->mouse();
414 | input_wrapper.controller = mouse;
415 |
416 | if (api->any_released(input_wrapper.controller) != UINT_MAX) {
417 | input_wrapper.time_since_pressed = -1;
418 | }
419 |
420 |
421 | if (debuginator_is_open(debuginator)) {
422 | CApiVector3 scroll = input_wrapper.axis("wheel");
423 | if (scroll.y != 0) {
424 | debuginator->focus_height += scroll.y * 0.05f;
425 | float max_height = debuginator_total_height(debuginator);
426 | int active_height = 0;
427 | debuginator__distance_to_hot_item(debuginator->root, debuginator->hot_item, debuginator->item_height, &active_height);
428 | float height_pixels = debuginator->focus_height * debuginator->size.y - active_height;
429 | if (height_pixels < -(max_height - (1.f - default_focus_height) * debuginator->size.y)) {
430 | debuginator->focus_height = -(max_height - (1.f - default_focus_height) * debuginator->size.y - active_height) / debuginator->size.y;
431 | } else if (height_pixels > default_focus_height * debuginator->size.y) {
432 | debuginator->focus_height = (default_focus_height * debuginator->size.y + active_height) / debuginator->size.y;
433 | }
434 | }
435 |
436 | if (input_wrapper.pressed_repeat("left")) {
437 | CApiVector3 pos = input_wrapper.axis("cursor");
438 | float y = debuginator->screen_resolution.y - pos.y;
439 | if (pos.x > debuginator->top_left.x && pos.x < debuginator->top_left.x + debuginator->size.x) {
440 | debuginator_activate_closest_by_height(debuginator, y);
441 | }
442 | }
443 | }
444 | }
445 |
446 | if (devices & Debuginator_Gamepad) {
447 | int xbox_style_pads = 0;
448 |
449 | #if !defined(PS4)
450 | xbox_style_pads = script_api->Input->num_pads();
451 | #endif
452 | for (int i = 0; i < xbox_style_pads; i++) {
453 | input_wrapper.controller = script_api->Input->pad(i);
454 |
455 | if (!api->active(input_wrapper.controller)) {
456 | continue;
457 | }
458 |
459 | if (api->any_released(input_wrapper.controller) != UINT_MAX) {
460 | input_wrapper.time_since_pressed = -1;
461 | }
462 |
463 | if (!debuginator_is_open(debuginator)) {
464 | if (input_wrapper.pressed("start")) {
465 | debuginator_set_open(debuginator, true);
466 | }
467 |
468 | continue;
469 | }
470 |
471 | CApiVector3 left_stick = input_wrapper.axis("left");
472 | float DEADZONE = 0.4f;
473 | if (fabs(left_stick.x) > DEADZONE) {
474 | if (wrapper->axis_selected_repeat) {
475 | left_stick.x = 0.f;
476 | } else {
477 | wrapper->axis_selected_repeat = true;
478 | }
479 | } else {
480 | wrapper->axis_selected_repeat = false;
481 | }
482 | float SCROLL_TIMEOUT = 0.25f;
483 | float SCROLL_REPEAT_TIMEOUT = 0.05f;
484 | if (fabs(left_stick.y) > DEADZONE) {
485 | if (wrapper->axis_scroll_repeat && wrapper->scroll_repeat_timer < 0.f) {
486 | left_stick.y = 0.f;
487 | } else if (!wrapper->axis_scroll_repeat) {
488 | wrapper->scroll_repeat_timer = -SCROLL_TIMEOUT;
489 | wrapper->axis_scroll_repeat = true;
490 | } else {
491 | wrapper->scroll_repeat_timer = -SCROLL_REPEAT_TIMEOUT;
492 | wrapper->axis_scroll_repeat = true;
493 | }
494 | } else {
495 | wrapper->axis_scroll_repeat = false;
496 | }
497 |
498 | if (input_wrapper.pressed_repeat("d_up") || left_stick.y > DEADZONE) {
499 | bool long_move = false;
500 | debuginator_move_to_prev_leaf(debuginator, long_move);
501 | }
502 | else if (input_wrapper.pressed_repeat("d_down") || left_stick.y < -DEADZONE) {
503 | bool long_move = false;
504 | debuginator_move_to_next_leaf(debuginator, long_move);
505 | }
506 | else if (input_wrapper.pressed("d_left") || input_wrapper.pressed("b")) {
507 | DebuginatorItem* hot_item = debuginator_get_hot_item(debuginator);
508 | if (debuginator_is_open(debuginator) && !hot_item->leaf.is_expanded) {
509 | debuginator_set_open(debuginator, false);
510 | }
511 | else if (!hot_item->is_folder && hot_item->leaf.is_expanded) {
512 | debuginator_move_to_parent(debuginator);
513 | }
514 | }
515 | else if (input_wrapper.pressed("start")) {
516 | debuginator_set_open(debuginator, false);
517 | }
518 | else if (input_wrapper.pressed("d_right") || input_wrapper.pressed("a") || fabs(left_stick.x) > DEADZONE) {
519 | debuginator_move_to_child(debuginator, false);
520 | }
521 | else if (input_wrapper.pressed_repeat("left_shoulder")) {
522 | bool long_move = true;
523 | debuginator_move_to_prev_leaf(debuginator, long_move);
524 | debuginator->focus_height = default_focus_height;
525 | }
526 | else if (input_wrapper.pressed_repeat("right_shoulder")) {
527 | bool long_move = true;
528 | debuginator_move_to_next_leaf(debuginator, long_move);
529 | debuginator->focus_height = default_focus_height;
530 | }
531 | else if (input_wrapper.pressed("x")) {
532 | debuginator_move_to_child(debuginator, true);
533 | }
534 | }
535 |
536 | // Todo generalize this
537 | int num_ps4_pads = 0;
538 | #if defined(WINDOWSPC)
539 | num_ps4_pads = script_api->Input->num_windows_ps4_pads();
540 | #elif defined(PS4)
541 | num_ps4_pads = script_api->Input->num_pads();
542 | #endif
543 | for (int i = 0; i < num_ps4_pads; i++) {
544 | #if defined(WINDOWSPC)
545 | input_wrapper.controller = script_api->Input->windows_ps4_pad(i);
546 | #else
547 | input_wrapper.controller = script_api->Input->pad(i);
548 | #endif
549 |
550 | if (!api->active(input_wrapper.controller)) {
551 | continue;
552 | }
553 |
554 | if (api->any_released(input_wrapper.controller) != UINT_MAX) {
555 | input_wrapper.time_since_pressed = -1;
556 | }
557 |
558 | if (!debuginator_is_open(debuginator)) {
559 | if (input_wrapper.pressed("options")) {
560 | debuginator_set_open(debuginator, true);
561 | }
562 |
563 | continue;
564 | }
565 |
566 | CApiVector3 left_stick = input_wrapper.axis("left");
567 | float DEADZONE = 0.4f;
568 | if (fabs(left_stick.x) > DEADZONE) {
569 | if (wrapper->axis_selected_repeat) {
570 | left_stick.x = 0.f;
571 | } else {
572 | wrapper->axis_selected_repeat = true;
573 | }
574 | } else {
575 | wrapper->axis_selected_repeat = false;
576 | }
577 | float SCROLL_TIMEOUT = 0.25f;
578 | float SCROLL_REPEAT_TIMEOUT = 0.05f;
579 | if (fabs(left_stick.y) > DEADZONE) {
580 | if (wrapper->axis_scroll_repeat && wrapper->scroll_repeat_timer < 0.f) {
581 | left_stick.y = 0.f;
582 | } else if (!wrapper->axis_scroll_repeat) {
583 | wrapper->scroll_repeat_timer = -SCROLL_TIMEOUT;
584 | wrapper->axis_scroll_repeat = true;
585 | } else {
586 | wrapper->scroll_repeat_timer = -SCROLL_REPEAT_TIMEOUT;
587 | wrapper->axis_scroll_repeat = true;
588 | }
589 | } else {
590 | wrapper->axis_scroll_repeat = false;
591 | }
592 |
593 | if (input_wrapper.pressed_repeat("up") || left_stick.y > DEADZONE) {
594 | bool long_move = false;
595 | debuginator_move_to_prev_leaf(debuginator, long_move);
596 | }
597 | else if (input_wrapper.pressed_repeat("down") || left_stick.y < -DEADZONE) {
598 | bool long_move = false;
599 | debuginator_move_to_next_leaf(debuginator, long_move);
600 | }
601 | else if (input_wrapper.pressed("left") || input_wrapper.pressed("circle")) {
602 | DebuginatorItem* hot_item = debuginator_get_hot_item(debuginator);
603 | if (debuginator_is_open(debuginator) && !hot_item->leaf.is_expanded) {
604 | debuginator_set_open(debuginator, false);
605 | }
606 | else if (!hot_item->is_folder && hot_item->leaf.is_expanded) {
607 | debuginator_move_to_parent(debuginator);
608 | }
609 | }
610 | else if (input_wrapper.pressed("options")) {
611 | debuginator_set_open(debuginator, false);
612 | }
613 | else if (input_wrapper.pressed("right") || input_wrapper.pressed("cross") || fabs(left_stick.x) > DEADZONE) {
614 | debuginator_move_to_child(debuginator, false);
615 | }
616 | else if (input_wrapper.pressed_repeat("l1")) {
617 | bool long_move = true;
618 | debuginator_move_to_prev_leaf(debuginator, long_move);
619 | }
620 | else if (input_wrapper.pressed_repeat("r1")) {
621 | bool long_move = true;
622 | debuginator_move_to_next_leaf(debuginator, long_move);
623 | }
624 | else if (input_wrapper.pressed("square")) {
625 | debuginator_move_to_child(debuginator, true);
626 | }
627 | }
628 | }
629 | }
630 |
631 | void set_ui_size(TheDebuginator* debuginator, int font_size, int item_height) {
632 | if (debuginator == NULL) {
633 | debuginator = get_debuginator("default");
634 | }
635 |
636 | debuginator_set_item_height(debuginator, item_height);
637 |
638 | TheDebuginatorWrapper* wrapper = (TheDebuginatorWrapper*)debuginator;
639 | wrapper->font_size = font_size;
640 | }
641 |
642 | void get_debuginator_api(TheDebuginatorApi* api) {
643 | api->create_debuginator = create_debuginator;
644 | api->destroy_debuginator = destroy_debuginator;
645 | api->get_debuginator = get_debuginator;
646 | api->handle_default_input = handle_default_input;
647 |
648 | api->get_default_config = debuginator_get_default_config;
649 | api->is_open = debuginator_is_open;
650 | api->set_open = debuginator_set_open;
651 | api->create_array_item = debuginator_create_array_item;
652 | api->create_bool_item = debuginator_create_bool_item;
653 | api->create_preset_item = debuginator_create_preset_item;
654 | api->new_folder_item = debuginator_new_folder_item;
655 | api->get_item = debuginator_get_item;
656 | api->set_hot_item = debuginator_set_hot_item;
657 | api->get_hot_item = debuginator_get_hot_item;
658 | api->remove_item = debuginator_remove_item;
659 | api->remove_item_by_path = debuginator_remove_item_by_path;
660 | api->save = debuginator_save;
661 | api->load_item = debuginator_load_item;
662 | api->set_default_value = debuginator_set_default_value;
663 | api->set_edit_type = debuginator_set_edit_type;
664 | api->activate = debuginator_activate;
665 | api->move_to_next_leaf = debuginator_move_to_next_leaf;
666 | api->move_to_prev_leaf = debuginator_move_to_prev_leaf;
667 | api->move_to_child = debuginator_move_to_child;
668 | api->move_to_parent = debuginator_move_to_parent;
669 | api->is_filtering_enabled = debuginator_is_filtering_enabled;
670 | api->set_filtering_enabled = debuginator_set_filtering_enabled;
671 | api->get_filter = debuginator_get_filter;
672 | api->update_filter = debuginator_update_filter;
673 | api->set_item_height = debuginator_set_item_height;
674 | api->set_size = debuginator_set_size;
675 | }
676 |
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/c_api_the_debuginator.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define THE_DEBUGINATOR_API_ID 0x0ac5036c // 0x0ac5036c049d75bf
4 |
5 | #include "the_debuginator.h"
6 | #include
7 |
8 | #ifdef __cplusplus
9 | extern "C" {
10 | #endif
11 |
12 | typedef struct CApiWindow CApiWindow;
13 | typedef const CApiWindow* ConstWindowPtr;
14 | typedef struct CApiGui* GuiPtr;
15 | typedef struct CApiMaterial* MaterialPtr;
16 | typedef void *(*GetApiFunction)(unsigned api);
17 |
18 | typedef struct DebuginatorPluginCreateContext {
19 | TheDebuginatorConfig config;
20 | ConstWindowPtr window;
21 | GuiPtr gui;
22 | uint64_t font;
23 | MaterialPtr font_material;
24 | int font_size;
25 | } DebuginatorPluginCreateContext;
26 |
27 | typedef enum DebuginatorInputDevices {
28 | Debuginator_Keyboard = 1 << 0,
29 | Debuginator_Gamepad = 1 << 1,
30 | Debuginator_Mouse = 1 << 2,
31 | Debuginator_Touch = 1 << 3,
32 | } DebuginatorInputDevices;
33 |
34 | typedef struct TheDebuginatorApi {
35 | // Plugin API
36 | TheDebuginator*(*create_debuginator)(const char* id, DebuginatorPluginCreateContext* context);
37 | TheDebuginator*(*get_debuginator)(const char* id);
38 | void(*destroy_debuginator)(TheDebuginator* debuginator);
39 |
40 | void(*handle_default_input)(TheDebuginator* debuginator, unsigned devices);
41 | void(*set_ui_size)(TheDebuginator* debuginator, int font_size, int item_height);
42 |
43 | // Direct Debuginator API
44 | void(*get_default_config)(TheDebuginatorConfig* config);
45 | bool(*is_open)(TheDebuginator* debuginator);
46 | void(*set_open)(TheDebuginator* debuginator, bool open);
47 |
48 | DebuginatorItem*(*create_array_item)(TheDebuginator* debuginator,
49 | DebuginatorItem* parent, const char* path, const char* description,
50 | DebuginatorOnItemChangedCallback on_item_changed_callback, void* user_data,
51 | const char** value_titles, void* values, int num_values, int value_size);
52 |
53 | DebuginatorItem*(*create_bool_item)(TheDebuginator* debuginator, const char* path, const char* description, void* user_data);
54 | DebuginatorItem*(*create_preset_item)(TheDebuginator* debuginator, const char* path, const char** paths, const char** value_titles, int** value_indices, int num_paths);
55 |
56 | DebuginatorItem*(*new_folder_item)(TheDebuginator* debuginator, DebuginatorItem* parent, const char* title, int title_length);
57 | DebuginatorItem*(*get_item)(TheDebuginator* debuginator, DebuginatorItem* parent, const char* path, bool create_if_not_exist);
58 | void(*set_hot_item)(TheDebuginator* debuginator, const char* path);
59 | DebuginatorItem*(*get_hot_item)(TheDebuginator* debuginator);
60 | void(*remove_item)(TheDebuginator* debuginator, DebuginatorItem* item);
61 | void(*remove_item_by_path)(TheDebuginator* debuginator, const char* path);
62 |
63 | int(*save)(TheDebuginator* debuginator, DebuginatorSaveItemCallback callback, char* save_buffer, int save_buffer_size);
64 | void(*load_item)(TheDebuginator* debuginator, const char* path, const char* value_title);
65 | void(*set_default_value)(TheDebuginator* debuginator, const char* path, const char* value_title, int value_index); // value index is used if value_title == NULL
66 | void(*set_edit_type)(TheDebuginator* debuginator, const char* path, DebuginatorItemEditorDataType edit_type);
67 |
68 | void(*activate)(TheDebuginator* debuginator, DebuginatorItem* item, bool animate);
69 | void(*move_to_next_leaf)(TheDebuginator* debuginator, bool long_move);
70 | void(*move_to_prev_leaf)(TheDebuginator* debuginator, bool long_move);
71 | void(*move_to_child)(TheDebuginator* debuginator, bool toggle_and_activate);
72 | void(*move_to_parent)(TheDebuginator* debuginator);
73 |
74 | bool(*is_filtering_enabled)(TheDebuginator* debuginator);
75 | void(*set_filtering_enabled)(TheDebuginator* debuginator, bool enabled);
76 | const char*(*get_filter)(TheDebuginator* debuginator);
77 | void(*update_filter)(TheDebuginator* debuginator, const char* wanted_filter);
78 |
79 | void(*set_item_height)(TheDebuginator* debuginator, int item_height);
80 | void(*set_size)(TheDebuginator* debuginator, int width, int height);
81 | } TheDebuginatorApi;
82 |
83 | void get_debuginator_api(TheDebuginatorApi* api);
84 | void setup_api(GetApiFunction get_engine_api, const char* plugin_name);
85 | void shutdown_api();
86 | void update_debuginators(float dt);
87 |
88 | void* start_reload(GetApiFunction get_engine_api);
89 | void finish_reload(GetApiFunction get_engine_api, void *state);
90 |
91 | #ifdef __cplusplus
92 | }
93 | #endif
94 |
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/copy_latest_debuginator_h.bat:
--------------------------------------------------------------------------------
1 | REM This is kind of an ugly solution but it's the one with the least resistance...
2 |
3 | copy /Y /V ..\..\..\the_debuginator.h .\the_debuginator.h
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/resource.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | //{{NO_DEPENDENCIES}}
4 | // Microsoft Visual C++ generated include file.
5 | // Used by wwise_plugin.rc
6 | //
7 | #define VS_VERSION_INFO 1
8 |
9 | // Next default values for new objects
10 | //
11 | #ifdef APSTUDIO_INVOKED
12 | #ifndef APSTUDIO_READONLY_SYMBOLS
13 | #define _APS_NEXT_RESOURCE_VALUE 101
14 | #define _APS_NEXT_COMMAND_VALUE 40001
15 | #define _APS_NEXT_CONTROL_VALUE 1001
16 | #define _APS_NEXT_SYMED_VALUE 101
17 | #endif
18 | #endif
19 |
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/the_debuginator_plugin.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "c_api_the_debuginator.h"
3 |
4 | #include
5 | #include
6 |
7 | /* PLUGIN API */
8 |
9 | const char* get_name() { return "the_debuginator_plugin"; }
10 |
11 | void setup_plugin(GetApiFunction get_engine_api)
12 | {
13 | setup_api(get_engine_api, get_name());
14 | }
15 |
16 | void shutdown_plugin()
17 | {
18 | shutdown_api();
19 | }
20 |
21 | void update_plugin(float dt)
22 | {
23 | update_debuginators(dt);
24 | }
25 |
26 | extern "C" {
27 |
28 | /**
29 | * Load and define plugin APIs.
30 | */
31 | PLUGIN_DLLEXPORT void *get_plugin_api(unsigned api)
32 | {
33 | if (api == PLUGIN_API_ID) {
34 | static PluginApi plugin_api = { 0 };
35 | plugin_api.get_name = get_name;
36 | plugin_api.setup_game = setup_plugin;
37 | plugin_api.update_game = update_plugin;
38 | plugin_api.shutdown_game = shutdown_plugin;
39 | return &plugin_api;
40 | }
41 | else if (api == THE_DEBUGINATOR_API_ID)
42 | {
43 | static TheDebuginatorApi debuginator_api = { 0 };
44 | get_debuginator_api(&debuginator_api);
45 | return &debuginator_api;
46 | }
47 |
48 | return nullptr;
49 | }
50 |
51 | }
52 |
53 | /* EXAMPLE */
54 |
55 | // #define DEBUGINATOR_EXAMPLE
56 | #if defined(DEBUGINATOR_EXAMPLE)
57 |
58 | #include "the_debuginator.h"
59 |
60 | void* get_engine_api(int id) { return NULL; };
61 |
62 | struct example_data {
63 | bool my_bool;
64 | bool limit_framerate;
65 | };
66 |
67 | static example_data my_userdata;
68 |
69 | void example() {
70 | PluginManagerApi *plugin_manager_api = (PluginManagerApi*)get_engine_api(PLUGIN_MANAGER_API_ID);
71 | TheDebuginatorApi* debuginator_api = (TheDebuginatorApi*)plugin_manager_api->get_next_plugin_api(THE_DEBUGINATOR_API_ID, NULL);
72 |
73 | int max_number_of_items = 100000;
74 | int width = 500;
75 | float focus_height = 0.6f;
76 | TheDebuginator* debuginator = debuginator_api->create_debuginator("Example", NULL, max_number_of_items, width, focus_height, &my_userdata);
77 |
78 | debuginator_create_bool_item(debuginator, "SDL Demo/Throttle framerate", "Disables sleeping between frames.", &my_userdata.limit_framerate);
79 |
80 | debuginator_api->destroy_debuginator(debuginator);
81 | }
82 | #endif
83 |
--------------------------------------------------------------------------------
/plugins/stingray/the_debuginator_plugin/the_debuginator_plugin.rc.in:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #include "resource.h"
4 |
5 | #define APSTUDIO_READONLY_SYMBOLS
6 | /////////////////////////////////////////////////////////////////////////////
7 | //
8 | // Generated from the TEXTINCLUDE 2 resource.
9 | //
10 | #include "windows.h"
11 |
12 | /////////////////////////////////////////////////////////////////////////////
13 | #undef APSTUDIO_READONLY_SYMBOLS
14 |
15 | /////////////////////////////////////////////////////////////////////////////
16 | // English (United States) resources
17 |
18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
20 | #pragma code_page(1252)
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""windows.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Version
51 | //
52 |
53 | VS_VERSION_INFO VERSIONINFO
54 | FILEVERSION @PRODUCT_VERSION_MAJOR@,@PRODUCT_VERSION_MINOR@,@PRODUCT_VERSION_TCID@,@PRODUCT_VERSION_REVISION@
55 | PRODUCTVERSION @PRODUCT_VERSION_MAJOR@,@PRODUCT_VERSION_MINOR@,@PRODUCT_VERSION_TCID@,@PRODUCT_VERSION_REVISION@
56 | FILEFLAGSMASK 0x3fL
57 | #ifdef _DEBUG
58 | FILEFLAGS 0x1L
59 | #else
60 | FILEFLAGS 0x0L
61 | #endif
62 | FILEOS 0x40004L
63 | FILETYPE 0x0L
64 | FILESUBTYPE 0x0L
65 | BEGIN
66 | BLOCK "StringFileInfo"
67 | BEGIN
68 | BLOCK "040904b0"
69 | BEGIN
70 | VALUE "CompanyName", "@PRODUCT_COMPANY@"
71 | VALUE "FileDescription", "@PROJECT_NAME@"
72 | VALUE "FileVersion", "@PRODUCT_VERSION_MAJOR@.@PRODUCT_VERSION_MINOR@.@PRODUCT_VERSION_TCID@.@PRODUCT_VERSION_REVISION@"
73 | VALUE "InternalName", "@PROJECT_NAME@"
74 | VALUE "LegalCopyright", "@PRODUCT_COPYRIGHT@"
75 | VALUE "ProductName", "@PRODUCT_COMPANY@ @PRODUCT_NAME@"
76 | VALUE "ProductVersion", "@PRODUCT_VERSION_MAJOR@.@PRODUCT_VERSION_MINOR@.@PRODUCT_VERSION_TCID@.@PRODUCT_VERSION_REVISION@"
77 | END
78 | END
79 | BLOCK "VarFileInfo"
80 | BEGIN
81 | VALUE "Translation", 0x409, 1200
82 | END
83 | END
84 |
85 | #endif // English (United States) resources
86 | /////////////////////////////////////////////////////////////////////////////
87 |
88 |
89 |
90 | #ifndef APSTUDIO_INVOKED
91 | /////////////////////////////////////////////////////////////////////////////
92 | //
93 | // Generated from the TEXTINCLUDE 3 resource.
94 | //
95 |
96 |
97 | /////////////////////////////////////////////////////////////////////////////
98 | #endif // not APSTUDIO_INVOKED
99 |
100 |
--------------------------------------------------------------------------------
/tests/3rdparty/SDL_GameControllerDB-master/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python: 3.5
3 | script: ./check.py gamecontrollerdb.txt
4 |
--------------------------------------------------------------------------------
/tests/3rdparty/SDL_GameControllerDB-master/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Simple DirectMedia Layer
3 | Copyright (C) 1997-2013 Sam Lantinga
4 |
5 | This software is provided 'as-is', without any express or implied
6 | warranty. In no event will the authors be held liable for any damages
7 | arising from the use of this software.
8 |
9 | Permission is granted to anyone to use this software for any purpose,
10 | including commercial applications, and to alter it and redistribute it
11 | freely, subject to the following restrictions:
12 |
13 | 1. The origin of this software must not be misrepresented; you must not
14 | claim that you wrote the original software. If you use this software
15 | in a product, an acknowledgment in the product documentation would be
16 | appreciated but is not required.
17 | 2. Altered source versions must be plainly marked as such, and must not be
18 | misrepresented as being the original software.
19 | 3. This notice may not be removed or altered from any source distribution.
20 |
21 |
--------------------------------------------------------------------------------
/tests/3rdparty/SDL_GameControllerDB-master/README.md:
--------------------------------------------------------------------------------
1 | ##SDL_GameControllerDB
2 |
3 | [](https://travis-ci.org/gabomdq/SDL_GameControllerDB)
4 |
5 | A community source database of game controller mappings to be used with SDL2 Game Controller functionality.
6 |
7 | ####Usage:
8 |
9 | Download gamecontrollerdb.txt, place it in your app's directory and load with:
10 |
11 | ```
12 | SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
13 | ```
14 |
15 | ####Creating new mappings:
16 |
17 | To create new mappings, you can use the controllermap utility provided with
18 | SDL2, or using Steam's Big Picture mode, configure your joystick and then
19 | look in config/config.vdf in your Steam installation directory for the
20 | SDL_GamepadBind entry.
21 |
22 | ####Checking your mappings:
23 | You need to have python3 installed. Run
24 |
25 | ```
26 | python3 check.py gamecontrollerdb.txt
27 | ```
28 |
29 | ####References:
30 |
31 | * [SDL2](http://www.libsdl.org)
32 | * [SDL_GameControllerAddMappingsFromFile](http://wiki.libsdl.org/SDL_GameControllerAddMappingsFromFile)
33 |
--------------------------------------------------------------------------------
/tests/3rdparty/SDL_GameControllerDB-master/check.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import fileinput
4 | import string
5 | import sys
6 |
7 | success = True
8 |
9 | def error (message):
10 | global success;
11 | success = False
12 | print("Error at #" + str(fileinput.lineno()), ":", message)
13 | print(line)
14 |
15 | def check_guid (guid):
16 | if len (guid) != 32:
17 | error ("The length of the guid string must be equal to 32")
18 | for c in guid:
19 | if not c in string.hexdigits:
20 | error ("Each character in guid string must be a hex character " + string.hexdigits)
21 |
22 | def check_mapping (mappingstring):
23 | keys = ["platform", "leftx", "lefty", "rightx", "righty", "a", "b", "back", "dpdown", \
24 | "dpleft", "dpright", "dpup", "guide", "leftshoulder", "leftstick", \
25 | "lefttrigger", "rightshoulder", "rightstick", "righttrigger", "start", "x", "y"]
26 | platforms = ["Linux", "Mac OS X", "Windows"]
27 | mappings = mappingstring.split (',')
28 | for mapping in mappings:
29 | if not mapping:
30 | continue
31 | if len (mapping.split(':')) != 2:
32 | error ("Invalid mapping : " + mapping)
33 | continue
34 | key = mapping.split (':')[0]
35 | value = mapping.split (':')[1]
36 | if not key in keys:
37 | error ("Invalid key \"" + key + "\" in mapping string")
38 |
39 | # Check values
40 | if key == "platform":
41 | if value not in platforms:
42 | error ("Invalid platform \"" + value + "\" in mapping string")
43 | else:
44 | if not value:
45 | continue
46 | if not value[0] in ['a', 'h', 'b']:
47 | error ("Invalid value \"" + value + "\" for key \"" + key +
48 | "\". Should start with a, b, or h")
49 | elif value[0] in ['a', 'b']:
50 | if not value[1:].isnumeric():
51 | error ("Invalid value \"" + value + "\" for key \"" + key +
52 | "\". Should be followed by a number after 'a' or 'b'")
53 | else:
54 | dpad_positions = map(str, [0, 1, 2, 4, 8, 1|2, 2|4, 4|8, 8|1])
55 | dpad_index = value[1:].split ('.')[0]
56 | dpad_position = value[1:].split ('.')[1]
57 | if not dpad_index.isnumeric():
58 | error ("Invalid value \"" + value + "\" for key \"" + key +
59 | "\". Dpad index \"" + dpad_index + "\" should be a number")
60 | if not dpad_position in dpad_positions:
61 | error ("Invalid value \"" + value + "\" for key \"" + key +
62 | "\". Dpad position \"" + dpad_position + "\" should be one of" +
63 | ', '.join(dpad_positions))
64 |
65 | for line in fileinput.input():
66 | if line.startswith('#') or line == '\n':
67 | continue
68 | splitted = line[:-1].split(',', 2)
69 | if len(splitted) < 3 or not splitted[0] or not splitted[1] or not splitted[2]:
70 | error ("Either GUID/Name/Mappingstring is missing or empty")
71 | check_guid(splitted[0])
72 | check_mapping(splitted[2])
73 |
74 | if not success:
75 | sys.exit(1)
76 |
--------------------------------------------------------------------------------
/tests/3rdparty/Simple-SDL2-Audio/README.md:
--------------------------------------------------------------------------------
1 | # Simple SDL2 Audio
2 |
3 | ## About
4 |
5 | * A simple native SDL2 Audio library that has 2 files, and an easy to use interface.
6 | * This library works without SDL2 Mixer, and plays a single music file at a time, and unlimited sounds (Mixes audio natively without Mixer)
7 |
8 | ## Install
9 |
10 | * Include `src/audio.c` and `src/audio.h` in your project
11 |
12 | ## Examples
13 |
14 | * `src/test.c` shows all the functionality possible:
15 |
16 | Basic use case:
17 |
18 | ```c
19 | // Initialize SDL2 Audio only
20 | SDL_Init(SDL_INIT_AUDIO);
21 |
22 | // Initialize Simple-SDL2-Audio
23 | initAudio();
24 |
25 | // Play music and a sound
26 | playMusic("music/highlands.wav", SDL_MIX_MAXVOLUME);
27 | playSound("sounds/door1.wav", SDL_MIX_MAXVOLUME / 2);
28 |
29 | // Let play for 1 second
30 | SDL_Delay(1000);
31 |
32 | // End Simple-SDL2-Audio
33 | endAudio();
34 |
35 | // End SDL2
36 | SDL_Quit();
37 | ```
38 |
39 | ## API Functions:
40 |
41 | ```c
42 | // Initialize Simple-SDL2-Audio on default audio device
43 | void initAudio(void);
44 |
45 | // Play many Sounds or single Musics
46 | void playSound(const char * filename, int volume);
47 | void playMusic(const char * filename, int volume);
48 |
49 | // Clean up Simple-SDL2-Audio
50 | void endAudio(void);
51 |
52 | // Pause or Unpause running audio
53 | void pauseAudio(void);
54 | void unpauseAudio(void);
55 |
56 | // Advanced functions used for caching WAV files in memory, create, play many times, free
57 | Audio * createAudio(const char * filename, uint8_t loop, int volume);
58 | void playSoundFromMemory(Audio * audio, int volume);
59 | void playMusicFromMemory(Audio * audio, int volume);
60 | void freeAudio(Audio * audio);
61 | ```
62 |
63 | ## Difference between Music vs Sound
64 |
65 | * Only one music can play at a time, and it loops (to close music you can just run `endAudio()`, or use `pauseAudio()` and `unpauseAudio()`).
66 | * If you add another music when one is playing, the first one fades out before ending, and then playing the second.
67 | * If you play more than 2 music at once, the first fades as expected, only the last music queued before the first fade out is used
68 |
69 | * Any number of sounds can be played at once, but obviously the more, can become distorted
70 | * Can change `AUDIO_MAX_SOUNDS` in `src/audio.c` to limit how many sounds can be played at once to reduce distortion from too many playing
71 |
72 | ## Caveats
73 |
74 | * This implementation uses SDL_MixAudioFormat for mixing for simplicity. It's noted "Do not use this function for mixing together more than two streams of sample data". While only playing 1 music removes a lot of these issues, if you need something more powerful you should write your own mixing function.
75 | * This implementation ONLY plays WAV files, and they should all be the same format, but can have differing formats if you play around with `SDL_AUDIO_ALLOW_CHANGES` in `src/audio.c`, see the top of `src/audio.c` to set the format, stereo vs mono etc... No conversion
76 | * Caching: Using the standard `playMusic()` functions makes a disk read each call. To only make one disk read, cache, and play the audio from memory, use the `createAudio(); playSoundFromMemory(); freeAudio();` functions (recommend storing the Audio* object in a dictionary / hashmap)
77 |
78 | ## Features to add
79 |
80 | * Pause / unpause only music, only sound or ~~both~~
81 | * Current implementation uses callback method, however in SDL 2.0.4 there exists `SDL_QueueAudio()` (no callback)
82 |
83 | ## Windows 7 Compatability
84 |
85 | * [Github Issue - Solution](https://github.com/jakebesworth/Simple-SDL2-Audio/issues/3)
86 |
87 | SDL2.0.6 updated how audio was handled, for Windows 7 using a later release of SDL2, you need to set `#define SDL_AUDIO_ALLOW_CHANGES SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE` which is a flag near the top of the file.
88 |
89 | ## Emscripten Compatibility
90 |
91 | * [Github Issue - Solution](https://github.com/jakebesworth/Simple-SDL2-Audio/issues/2)
92 |
93 | ## Resources
94 |
95 | * I made this project as a more modern version of https://gist.github.com/armornick/3447121
96 | * https://davidgow.net/handmadepenguin/ch7.html
97 | * http://rerwarwar.weebly.com/sdl2-audio.html
98 |
99 | ## Contributors
100 |
101 | * [Jake Besworth](https://github.com/jakebesworth)
102 | * [Lorenzo Mancini](https://github.com/lmancini)
103 | * [Ted](https://github.com/claimred)
104 | * [Eric Boez](https://github.com/ericb59)
105 |
--------------------------------------------------------------------------------
/tests/3rdparty/Simple-SDL2-Audio/src/simple_audio.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple-SDL2-Audio
3 | *
4 | * Copyright 2016 Jake Besworth
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include
25 |
26 | #include "simple_audio.h"
27 |
28 | /*
29 | * Native WAVE format
30 | *
31 | * On some GNU/Linux you can identify a files properties using:
32 | * mplayer -identify music.wav
33 | *
34 | * On some GNU/Linux to convert any music to this or another specified format use:
35 | * ffmpeg -i in.mp3 -acodec pcm_s16le -ac 2 -ar 48000 out.wav
36 | */
37 | /* SDL_AudioFormat of files, such as s16 little endian */
38 | #define AUDIO_FORMAT AUDIO_S16LSB
39 |
40 | /* Frequency of the file */
41 | #define AUDIO_FREQUENCY 48000
42 |
43 | /* 1 mono, 2 stereo, 4 quad, 6 (5.1) */
44 | #define AUDIO_CHANNELS 2
45 |
46 | /* Specifies a unit of audio data to be used at a time. Must be a power of 2 */
47 | #define AUDIO_SAMPLES 4096
48 |
49 | /* Max number of sounds that can be in the audio queue at anytime, stops too much mixing */
50 | #define AUDIO_MAX_SOUNDS 25
51 |
52 | /* Flags OR'd together, which specify how SDL should behave when a device cannot offer a specific feature
53 | * If flag is set, SDL will change the format in the actual audio file structure (as opposed to gDevice->want)
54 | *
55 | * Note: If you're having issues with Emscripten / EMCC play around with these flags
56 | *
57 | * 0 Allow no changes
58 | * SDL_AUDIO_ALLOW_FREQUENCY_CHANGE Allow frequency changes (e.g. AUDIO_FREQUENCY is 48k, but allow files to play at 44.1k
59 | * SDL_AUDIO_ALLOW_FORMAT_CHANGE Allow Format change (e.g. AUDIO_FORMAT may be S32LSB, but allow wave files of S16LSB to play)
60 | * SDL_AUDIO_ALLOW_CHANNELS_CHANGE Allow any number of channels (e.g. AUDIO_CHANNELS being 2, allow actual 1)
61 | * SDL_AUDIO_ALLOW_ANY_CHANGE Allow all changes above
62 | */
63 | // #define SDL_AUDIO_ALLOW_CHANGES SDL_AUDIO_ALLOW_ANY_CHANGE
64 | #define SDL_AUDIO_ALLOW_CHANGES SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE
65 |
66 | /*
67 | * Definition for the game global sound device
68 | *
69 | */
70 | typedef struct privateAudioDevice
71 | {
72 | SDL_AudioDeviceID device;
73 | SDL_AudioSpec want;
74 | uint8_t audioEnabled;
75 | } PrivateAudioDevice;
76 |
77 | /* File scope variables to persist data */
78 | static PrivateAudioDevice * gDevice;
79 | static uint32_t gSoundCount;
80 |
81 | /*
82 | * Add a music to the queue, addAudio wrapper for music due to fade
83 | *
84 | * @param new New Audio to add
85 | *
86 | */
87 | static void addMusic(Audio * root, Audio * new);
88 |
89 | /*
90 | * Wrapper function for playMusic, playSound, playMusicFromMemory, playSoundFromMemory
91 | *
92 | * @param filename Provide a filename to load WAV from, or NULL if using FromMemory
93 | * @param audio Provide an Audio object if copying from memory, or NULL if using a filename
94 | * @param sound 1 if looping (music), 0 otherwise (sound)
95 | * @param volume See playSound for explanation
96 | *
97 | */
98 | static inline void playAudio(const char * filename, Audio * audio, uint8_t loop, int volume);
99 |
100 | /*
101 | * Add a sound to the end of the queue
102 | *
103 | * @param root Root of queue
104 | * @param new New Audio to add
105 | *
106 | */
107 | static void addAudio(Audio * root, Audio * new);
108 |
109 | /*
110 | * Audio callback function for OpenAudioDevice
111 | *
112 | * @param userdata Points to linked list of sounds to play, first being a placeholder
113 | * @param stream Stream to mix sound into
114 | * @param len Length of sound to play
115 | *
116 | */
117 | static inline void audioCallback(void * userdata, uint8_t * stream, int len);
118 |
119 | void playSound(const char * filename, int volume)
120 | {
121 | playAudio(filename, NULL, 0, volume);
122 | }
123 |
124 | void playMusic(const char * filename, int volume)
125 | {
126 | playAudio(filename, NULL, 1, volume);
127 | }
128 |
129 | void playSoundFromMemory(Audio * audio, int volume)
130 | {
131 | playAudio(NULL, audio, 0, volume);
132 | }
133 |
134 | void playMusicFromMemory(Audio * audio, int volume)
135 | {
136 | playAudio(NULL, audio, 1, volume);
137 | }
138 |
139 | void initAudio(void)
140 | {
141 | Audio * global;
142 | gDevice = calloc(1, sizeof(PrivateAudioDevice));
143 | gSoundCount = 0;
144 |
145 | if(gDevice == NULL)
146 | {
147 | fprintf(stderr, "[%s: %d]Fatal Error: Memory c-allocation error\n", __FILE__, __LINE__);
148 | return;
149 | }
150 |
151 | gDevice->audioEnabled = 0;
152 |
153 | if(!(SDL_WasInit(SDL_INIT_AUDIO) & SDL_INIT_AUDIO))
154 | {
155 | fprintf(stderr, "[%s: %d]Error: SDL_INIT_AUDIO not initialized\n", __FILE__, __LINE__);
156 | return;
157 | }
158 |
159 | SDL_memset(&(gDevice->want), 0, sizeof(gDevice->want));
160 |
161 | (gDevice->want).freq = AUDIO_FREQUENCY;
162 | (gDevice->want).format = AUDIO_FORMAT;
163 | (gDevice->want).channels = AUDIO_CHANNELS;
164 | (gDevice->want).samples = AUDIO_SAMPLES;
165 | (gDevice->want).callback = audioCallback;
166 | (gDevice->want).userdata = calloc(1, sizeof(Audio));
167 |
168 | global = (gDevice->want).userdata;
169 |
170 | if(global == NULL)
171 | {
172 | fprintf(stderr, "[%s: %d]Error: Memory allocation error\n", __FILE__, __LINE__);
173 | return;
174 | }
175 |
176 | global->buffer = NULL;
177 | global->next = NULL;
178 |
179 | /* want.userdata = new; */
180 | if((gDevice->device = SDL_OpenAudioDevice(NULL, 0, &(gDevice->want), NULL, SDL_AUDIO_ALLOW_CHANGES)) == 0)
181 | {
182 | fprintf(stderr, "[%s: %d]Warning: failed to open audio device: %s\n", __FILE__, __LINE__, SDL_GetError());
183 | }
184 | else
185 | {
186 | /* Set audio device enabled global flag */
187 | gDevice->audioEnabled = 1;
188 |
189 | /* Unpause active audio stream */
190 | unpauseAudio();
191 | }
192 | }
193 |
194 | void endAudio(void)
195 | {
196 | if(gDevice->audioEnabled)
197 | {
198 | pauseAudio();
199 |
200 | freeAudio((Audio *) (gDevice->want).userdata);
201 |
202 | /* Close down audio */
203 | SDL_CloseAudioDevice(gDevice->device);
204 | }
205 |
206 | free(gDevice);
207 | }
208 |
209 | void pauseAudio(void)
210 | {
211 | if(gDevice->audioEnabled)
212 | {
213 | SDL_PauseAudioDevice(gDevice->device, 1);
214 | }
215 | }
216 |
217 | void unpauseAudio(void)
218 | {
219 | if(gDevice->audioEnabled)
220 | {
221 | SDL_PauseAudioDevice(gDevice->device, 0);
222 | }
223 | }
224 |
225 | void freeAudio(Audio * audio)
226 | {
227 | Audio * temp;
228 |
229 | while(audio != NULL)
230 | {
231 | if(audio->free == 1)
232 | {
233 | SDL_FreeWAV(audio->bufferTrue);
234 | }
235 |
236 | temp = audio;
237 | audio = audio->next;
238 |
239 | free(temp);
240 | }
241 | }
242 |
243 | Audio * createAudio(const char * filename, uint8_t loop, int volume)
244 | {
245 | Audio * new = calloc(1, sizeof(Audio));
246 |
247 | if(new == NULL)
248 | {
249 | fprintf(stderr, "[%s: %d]Error: Memory allocation error\n", __FILE__, __LINE__);
250 | return NULL;
251 | }
252 |
253 | if(filename == NULL)
254 | {
255 | fprintf(stderr, "[%s: %d]Warning: filename NULL: %s\n", __FILE__, __LINE__, filename);
256 | return NULL;
257 | }
258 |
259 | new->next = NULL;
260 | new->loop = loop;
261 | new->fade = 0;
262 | new->free = 1;
263 | new->volume = (uint8_t)volume;
264 |
265 | if(SDL_LoadWAV(filename, &(new->audio), &(new->bufferTrue), &(new->lengthTrue)) == NULL)
266 | {
267 | fprintf(stderr, "[%s: %d]Warning: failed to open wave file: %s error: %s\n", __FILE__, __LINE__, filename, SDL_GetError());
268 | free(new);
269 | return NULL;
270 | }
271 |
272 | new->buffer = new->bufferTrue;
273 | new->length = new->lengthTrue;
274 | (new->audio).callback = NULL;
275 | (new->audio).userdata = NULL;
276 |
277 | return new;
278 | }
279 |
280 | static inline void playAudio(const char * filename, Audio * audio, uint8_t loop, int volume)
281 | {
282 | Audio * new;
283 |
284 | /* Check if audio is enabled */
285 | if(!gDevice->audioEnabled)
286 | {
287 | return;
288 | }
289 |
290 | /* If sound, check if under max number of sounds allowed, else don't play */
291 | if(loop == 0)
292 | {
293 | if(gSoundCount >= AUDIO_MAX_SOUNDS)
294 | {
295 | return;
296 | }
297 | else
298 | {
299 | gSoundCount++;
300 | }
301 | }
302 |
303 | /* Load from filename or from Memory */
304 | if(filename != NULL)
305 | {
306 | /* Create new music sound with loop */
307 | new = createAudio(filename, loop, volume);
308 | }
309 | else if(audio != NULL)
310 | {
311 | new = malloc(sizeof(Audio));
312 |
313 | if(new == NULL)
314 | {
315 | fprintf(stderr, "[%s: %d]Fatal Error: Memory allocation error\n", __FILE__, __LINE__);
316 | return;
317 | }
318 |
319 | memcpy(new, audio, sizeof(Audio));
320 |
321 | new->volume = (uint8_t)volume;
322 | new->loop = loop;
323 | new->free = 0;
324 | }
325 | else
326 | {
327 | fprintf(stderr, "[%s: %d]Warning: filename and Audio parameters NULL\n", __FILE__, __LINE__);
328 | return;
329 | }
330 |
331 | /* Lock callback function */
332 | SDL_LockAudioDevice(gDevice->device);
333 |
334 | if(loop == 1)
335 | {
336 | addMusic((Audio *) (gDevice->want).userdata, new);
337 | }
338 | else
339 | {
340 | addAudio((Audio *) (gDevice->want).userdata, new);
341 | }
342 |
343 | SDL_UnlockAudioDevice(gDevice->device);
344 |
345 | }
346 |
347 | static void addMusic(Audio * root, Audio * new)
348 | {
349 | uint8_t musicFound = 0;
350 | Audio * rootNext = root->next;
351 |
352 | /* Find any existing musics, 0, 1 or 2 and fade them out */
353 | while(rootNext != NULL)
354 | {
355 | /* Phase out any current music */
356 | if(rootNext->loop == 1 && rootNext->fade == 0)
357 | {
358 | if(musicFound)
359 | {
360 | rootNext->length = 0;
361 | rootNext->volume = 0;
362 | }
363 |
364 | rootNext->fade = 1;
365 | }
366 | /* Set flag to remove any queued up music in favour of new music */
367 | else if(rootNext->loop == 1 && rootNext->fade == 1)
368 | {
369 | musicFound = 1;
370 | }
371 |
372 | rootNext = rootNext->next;
373 | }
374 |
375 | addAudio(root, new);
376 | }
377 |
378 | static inline void audioCallback(void * userdata, uint8_t * stream, int len)
379 | {
380 | Audio * audio = (Audio *) userdata;
381 | Audio * previous = audio;
382 | int tempLength;
383 | uint8_t music = 0;
384 |
385 | /* Silence the main buffer */
386 | SDL_memset(stream, 0, len);
387 |
388 | /* First one is place holder */
389 | audio = audio->next;
390 |
391 | while(audio != NULL)
392 | {
393 | if(audio->length > 0)
394 | {
395 | if(audio->fade == 1 && audio->loop == 1)
396 | {
397 | music = 1;
398 |
399 | if(audio->volume > 0)
400 | {
401 | audio->volume--;
402 | }
403 | else
404 | {
405 | audio->length = 0;
406 | }
407 | }
408 |
409 | if(music && audio->loop == 1 && audio->fade == 0)
410 | {
411 | tempLength = 0;
412 | }
413 | else
414 | {
415 | tempLength = ((uint32_t) len > audio->length) ? audio->length : (uint32_t) len;
416 | }
417 |
418 | SDL_MixAudioFormat(stream, audio->buffer, AUDIO_FORMAT, tempLength, audio->volume);
419 |
420 | audio->buffer += tempLength;
421 | audio->length -= tempLength;
422 |
423 | previous = audio;
424 | audio = audio->next;
425 | }
426 | else if(audio->loop == 1 && audio->fade == 0)
427 | {
428 | audio->buffer = audio->bufferTrue;
429 | audio->length = audio->lengthTrue;
430 | }
431 | else
432 | {
433 | previous->next = audio->next;
434 |
435 | if(audio->loop == 0)
436 | {
437 | gSoundCount--;
438 | }
439 |
440 | audio->next = NULL;
441 | freeAudio(audio);
442 |
443 | audio = previous->next;
444 | }
445 | }
446 | }
447 |
448 | static void addAudio(Audio * root, Audio * new)
449 | {
450 | if(root == NULL)
451 | {
452 | return;
453 | }
454 |
455 | while(root->next != NULL)
456 | {
457 | root = root->next;
458 | }
459 |
460 | root->next = new;
461 | }
462 |
--------------------------------------------------------------------------------
/tests/3rdparty/Simple-SDL2-Audio/src/simple_audio.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple-SDL2-Audio
3 | *
4 | * Copyright 2016 Jake Besworth
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | *
18 | */
19 |
20 | /*
21 | * audio.h
22 | *
23 | * All audio related functions go here
24 | *
25 | */
26 | #ifndef SIMPLE_AUDIO_
27 | #define SIMPLE_AUDIO_
28 |
29 | #ifdef __cplusplus
30 | extern "C"
31 | {
32 | #endif
33 |
34 | #include
35 |
36 | /*
37 | * Queue structure for all loaded sounds
38 | *
39 | */
40 | typedef struct sound
41 | {
42 | uint32_t length;
43 | uint32_t lengthTrue;
44 | uint8_t * bufferTrue;
45 | uint8_t * buffer;
46 | uint8_t loop;
47 | uint8_t fade;
48 | uint8_t free;
49 | uint8_t volume;
50 |
51 | SDL_AudioSpec audio;
52 |
53 | struct sound * next;
54 | } Audio;
55 |
56 | /*
57 | * Create a Audio object
58 | *
59 | * @param filename Filename for the WAVE file to load
60 | * @param loop 0 ends after playing once (sound), 1 repeats and fades when other music added (music)
61 | * @param volume Volume, read playSound()
62 | *
63 | * @return returns a new Audio or NULL on failure, you must call freeAudio() on return Audio
64 | *
65 | */
66 | Audio * createAudio(const char * filename, uint8_t loop, int volume);
67 |
68 | /*
69 | * Frees as many chained Audios as given
70 | *
71 | * @param audio Chain of sounds to free
72 | *
73 | */
74 | void freeAudio(Audio * audio);
75 |
76 | /*
77 | * Play a wave file currently must be S16LE format 2 channel stereo
78 | *
79 | * @param filename Filename to open, use getAbsolutePath
80 | * @param volume Volume 0 - 128. SDL_MIX_MAXVOLUME constant for max volume
81 | *
82 | */
83 | void playSound(const char * filename, int volume);
84 |
85 | /*
86 | * Plays a new music, only 1 at a time plays
87 | *
88 | * @param filename Filename of the WAVE file to load
89 | * @param volume Volume read playSound for moree
90 | *
91 | */
92 | void playMusic(const char * filename, int volume);
93 |
94 | /*
95 | * Plays a sound from a createAudio object (clones), only 1 at a time plays
96 | * Advantage to this method is no more disk reads, only once, data is stored and constantly reused
97 | *
98 | * @param audio Audio object to clone and use
99 | * @param volume Volume read playSound for moree
100 | *
101 | */
102 | void playSoundFromMemory(Audio * audio, int volume);
103 |
104 | /*
105 | * Plays a music from a createAudio object (clones), only 1 at a time plays
106 | * Advantage to this method is no more disk reads, only once, data is stored and constantly reused
107 | *
108 | * @param audio Audio object to clone and use
109 | * @param volume Volume read playSound for moree
110 | *
111 | */
112 | void playMusicFromMemory(Audio * audio, int volume);
113 |
114 | /*
115 | * Free all audio related variables
116 | * Note, this needs to be run even if initAudio fails, because it frees the global audio device
117 | *
118 | */
119 | void endAudio(void);
120 |
121 | /*
122 | * Initialize Audio Variable
123 | *
124 | */
125 | void initAudio(void);
126 |
127 | /*
128 | * Pause audio from playing
129 | *
130 | */
131 | void pauseAudio(void);
132 |
133 | /*
134 | * Unpause audio from playing
135 | *
136 | */
137 | void unpauseAudio(void);
138 |
139 | #ifdef __cplusplus
140 | }
141 | #endif
142 |
143 | #endif
144 |
--------------------------------------------------------------------------------
/tests/3rdparty/kenney_interfacesounds/License.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | Interface Sounds (1.0)
4 |
5 | Created/distributed by Kenney (www.kenney.nl)
6 | Creation date: 11-02-2020
7 |
8 | ------------------------------
9 |
10 | License: (Creative Commons Zero, CC0)
11 | http://creativecommons.org/publicdomain/zero/1.0/
12 |
13 | This content is free to use in personal, educational and commercial projects.
14 | Support us by crediting Kenney or www.kenney.nl (this is not mandatory)
15 |
16 | ------------------------------
17 |
18 | Donate: http://support.kenney.nl
19 | Patreon: http://patreon.com/kenney/
20 |
21 | Follow on Twitter for updates:
22 | http://twitter.com/KenneyNL
--------------------------------------------------------------------------------
/tests/3rdparty/kenney_interfacesounds/bong_001.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/kenney_interfacesounds/bong_001.wav
--------------------------------------------------------------------------------
/tests/3rdparty/kenney_interfacesounds/pluck_001.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/kenney_interfacesounds/pluck_001.wav
--------------------------------------------------------------------------------
/tests/3rdparty/kenney_interfacesounds/pluck_002.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/kenney_interfacesounds/pluck_002.wav
--------------------------------------------------------------------------------
/tests/3rdparty/kenney_interfacesounds/select_007.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/kenney_interfacesounds/select_007.wav
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/AUTHORS:
--------------------------------------------------------------------------------
1 | AUTHORS
2 |
3 | Current Contributors (sorted alphabetically):
4 | - Pravin Satpute
5 | Project Owner (Current)
6 | Red Hat, Inc.
7 |
8 | Previous Contributors
9 |
10 | - Steve Matteson
11 | Original Designer
12 | Ascender, Inc.
13 |
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/ChangeLog:
--------------------------------------------------------------------------------
1 | * Thu Oct 04 2012 Pravin Satpute
2 | - Resolved "Glyphs with multiple unicode encodings inhibit subsetting" #851790
3 | - Resolved #851791, #854601 and #851825
4 | - Following GASP table version as per Liberation old version. (Anti-aliasing disabled)
5 | - Added support for Serbian glyphs for wikipedia #657849
6 | - In Monospace fonts, isFixedPitch bit set via script for getting it recognized as Monospace in putty.exe
7 |
8 | * Fri Jul 06 2012 Pravin Satpute
9 | - Initial version of Liberation fonts based on croscore fonts version 1.21.0
10 | - Converted TTF files into SFD files to be open source.
11 | - Update Copyright and License file
12 | - set fsType bit to 0, Installable Embedding is allowed.
13 | - Absolute value in HHeadAscent/Descent values for maintaining Metric compatibility.
14 |
15 |
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LICENSE:
--------------------------------------------------------------------------------
1 | Digitized data copyright (c) 2010 Google Corporation
2 | with Reserved Font Arimo, Tinos and Cousine.
3 | Copyright (c) 2012 Red Hat, Inc.
4 | with Reserved Font Name Liberation.
5 |
6 | This Font Software is licensed under the SIL Open Font License,
7 | Version 1.1.
8 |
9 | This license is copied below, and is also available with a FAQ at:
10 | http://scripts.sil.org/OFL
11 |
12 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
13 |
14 | PREAMBLE The goals of the Open Font License (OFL) are to stimulate
15 | worldwide development of collaborative font projects, to support the font
16 | creation efforts of academic and linguistic communities, and to provide
17 | a free and open framework in which fonts may be shared and improved in
18 | partnership with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves.
22 | The fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply to
27 | any document created using the fonts or their derivatives.
28 |
29 |
30 |
31 | DEFINITIONS
32 | "Font Software" refers to the set of files released by the Copyright
33 | Holder(s) under this license and clearly marked as such.
34 | This may include source files, build scripts and documentation.
35 |
36 | "Reserved Font Name" refers to any names specified as such after the
37 | copyright statement(s).
38 |
39 | "Original Version" refers to the collection of Font Software components
40 | as distributed by the Copyright Holder(s).
41 |
42 | "Modified Version" refers to any derivative made by adding to, deleting,
43 | or substituting ? in part or in whole ?
44 | any of the components of the Original Version, by changing formats or
45 | by porting the Font Software to a new environment.
46 |
47 | "Author" refers to any designer, engineer, programmer, technical writer
48 | or other person who contributed to the Font Software.
49 |
50 |
51 | PERMISSION & CONDITIONS
52 |
53 | Permission is hereby granted, free of charge, to any person obtaining a
54 | copy of the Font Software, to use, study, copy, merge, embed, modify,
55 | redistribute, and sell modified and unmodified copies of the Font
56 | Software, subject to the following conditions:
57 |
58 | 1) Neither the Font Software nor any of its individual components,in
59 | Original or Modified Versions, may be sold by itself.
60 |
61 | 2) Original or Modified Versions of the Font Software may be bundled,
62 | redistributed and/or sold with any software, provided that each copy
63 | contains the above copyright notice and this license. These can be
64 | included either as stand-alone text files, human-readable headers or
65 | in the appropriate machine-readable metadata fields within text or
66 | binary files as long as those fields can be easily viewed by the user.
67 |
68 | 3) No Modified Version of the Font Software may use the Reserved Font
69 | Name(s) unless explicit written permission is granted by the
70 | corresponding Copyright Holder. This restriction only applies to the
71 | primary font name as presented to the users.
72 |
73 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
74 | Software shall not be used to promote, endorse or advertise any
75 | Modified Version, except to acknowledge the contribution(s) of the
76 | Copyright Holder(s) and the Author(s) or with their explicit written
77 | permission.
78 |
79 | 5) The Font Software, modified or unmodified, in part or in whole, must
80 | be distributed entirely under this license, and must not be distributed
81 | under any other license. The requirement for fonts to remain under
82 | this license does not apply to any document created using the Font
83 | Software.
84 |
85 |
86 |
87 | TERMINATION
88 | This license becomes null and void if any of the above conditions are not met.
89 |
90 |
91 |
92 | DISCLAIMER
93 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
94 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
95 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
96 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
97 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
98 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
99 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
100 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER
101 | DEALINGS IN THE FONT SOFTWARE.
102 |
103 |
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Bold.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-BoldItalic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Italic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationMono-Regular.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Bold.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-BoldItalic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Italic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSans-Regular.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Bold.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-BoldItalic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-BoldItalic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Italic.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/3rdparty/liberation-fonts-ttf-2.00.1/LiberationSerif-Regular.ttf
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/README:
--------------------------------------------------------------------------------
1 | 1. What's this?
2 | =================
3 |
4 | The Liberation Fonts is font collection which aims to provide document
5 | layout compatibility as usage of Times New Roman, Arial, Courier New.
6 |
7 |
8 | 2. Requirements
9 | =================
10 |
11 | * fontforge is installed.
12 | (http://fontforge.sourceforge.net)
13 |
14 |
15 | 3. Install
16 | ============
17 |
18 | 3.1 Decompress tarball
19 |
20 | You can extract the files by following command:
21 |
22 | $ tar zxvf liberation-fonts-[VERSION].tar.gz
23 |
24 | 3.2 Build from the source
25 |
26 | Change into directory liberation-fonts-[VERSION]/ and build from sources by
27 | following commands:
28 |
29 | $ cd liberation-fonts-[VERSION]
30 | $ make
31 |
32 | The built font files will be available in 'build' directory.
33 |
34 | 3.3 Install to system
35 |
36 | For Fedora, you could manually install the fonts by copying the TTFs to
37 | ~/.fonts for user wide usage, or to /usr/share/fonts/truetype/liberation
38 | for system-wide availability. Then, run "fc-cache" to let that cached.
39 |
40 | For other distributions, please check out corresponding documentation.
41 |
42 |
43 | 4. Usage
44 | ==========
45 |
46 | Simply select preferred liberation font in applications and start using.
47 |
48 |
49 | 5. License
50 | ============
51 |
52 | This Font Software is licensed under the SIL Open Font License,
53 | Version 1.1.
54 |
55 | Please read file "LICENSE" for details.
56 |
57 |
58 | 6. For Maintainers
59 | ====================
60 |
61 | Before packaging a new release based on a new source tarball, you have to
62 | update the version suffix in the Makefile:
63 |
64 | VER = [VERSION]
65 |
66 | Make sure that the defined version corresponds to the font software metadata
67 | which you can check with ftinfo/otfinfo or fontforge itself. It is highly
68 | recommended that file 'ChangeLog' is updated to reflect changes.
69 |
70 | Create a tarball with the following command:
71 |
72 | $ make dist
73 |
74 | The new versioned tarball will be available in the dist/ folder as
75 | 'liberation-fonts-[NEW_VERSION].tar.gz'.
76 |
77 | 7. Credits
78 | ============
79 |
80 | Please read file "AUTHORS" for list of contributors.
81 |
--------------------------------------------------------------------------------
/tests/3rdparty/liberation-fonts-ttf-2.00.1/TODO:
--------------------------------------------------------------------------------
1 | Here are todo for next release
2 | 1) Serbian glyph for wikipedia https://bugzilla.redhat.com/show_bug.cgi?id=657849
3 | - Improving shape of S_BE https://bugzilla.redhat.com/show_bug.cgi?id=657849#c96
4 | 2) Liberation Mono not recognizing as Mono in Windows application #861003
5 | - presently it is patch, we have to update zero width characters to fixed width
6 |
--------------------------------------------------------------------------------
/tests/sdl/demo.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "../../the_debuginator.h"
3 |
4 | //#include
5 | #include
6 | #include
7 |
8 | #include "demo.h"
9 |
10 | void demo_trigger_next(DemoData* data) {
11 | if (data->current_slide == -1) {
12 | data->current_slide = 0;
13 |
14 | for (int i=0; i < data->num_slides; ++i) {
15 | DemoSlide& slide = data->slides[i];
16 | slide.num_texts_visible = 0;
17 | memset(slide.anim_times, 0, sizeof(slide.anim_times));
18 | }
19 |
20 | DemoSlide& slide = data->slides[data->current_slide];
21 | slide.num_texts_visible++;
22 |
23 | return;
24 | }
25 |
26 | DemoSlide& slide = data->slides[data->current_slide];
27 | if (slide.num_texts_visible == slide.num_texts) {
28 | if (data->current_slide != data->num_slides - 1) {
29 | data->current_slide++;
30 | data->slides[data->current_slide].num_texts_visible++;
31 | }
32 | else {
33 | data->current_slide = -1;
34 | }
35 | }
36 | else {
37 | slide.num_texts_visible++;
38 | }
39 | }
40 | static void on_demo_action(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
41 | (void)app_userdata;
42 | (void)value;
43 | DemoData* data = (DemoData*)item->user_data;
44 | if (strcmp(value_title, "Start") == 0) {
45 | demo_trigger_next(data);
46 | }
47 | if (strcmp(value_title, "Stop") == 0) {
48 | data->current_slide = -1;
49 | }
50 | if (strcmp(value_title, "Next") == 0) {
51 | demo_trigger_next(data);
52 | }
53 | if (strcmp(value_title, "Prev") == 0) {
54 | if (data->current_slide >= 0) {
55 | data->current_slide -= 1;
56 | }
57 | }
58 | }
59 |
60 | static void debug_menu_setup(TheDebuginator* debuginator, DemoData* data) {
61 | (void)data;
62 | {
63 | static const char* string_titles[4] = { "Start", "Stop", "Prev", "Next" };
64 | debuginator_create_array_item(debuginator, NULL, "SDL Demo/Slide show",
65 | "Presentation demo", on_demo_action, data,
66 | string_titles, NULL, 4, 0);
67 | debuginator_set_edit_type(debuginator, "SDL Demo/Slide show", DEBUGINATOR_EditTypeActionArray);
68 | }
69 | }
70 |
71 | static DemoData s_demo_data;
72 |
73 | static void presentation_setup(DemoData* data) {
74 | {
75 | DemoSlide& slide = data->slides[data->num_slides++];
76 | slide.texts[slide.num_texts++] = "Click to start slideshow!";
77 | }
78 | {
79 | DemoSlide& slide = data->slides[data->num_slides++];
80 | slide.texts[slide.num_texts++] = "What is it?";
81 | slide.texts[slide.num_texts++] = "- Open source C library";
82 | slide.texts[slide.num_texts++] = "- Debug menu for games";
83 | slide.texts[slide.num_texts++] = "- Feature rich";
84 | }
85 | {
86 | DemoSlide& slide = data->slides[data->num_slides++];
87 | slide.texts[slide.num_texts++] = "So what does it look like?";
88 | slide.texts[slide.num_texts++] = "- It's pretty sweet!";
89 | slide.texts[slide.num_texts++] = "- Press Right Arrow to open it!";
90 | }
91 | {
92 | DemoSlide& slide = data->slides[data->num_slides++];
93 | slide.texts[slide.num_texts++] = "Core UI features";
94 | slide.texts[slide.num_texts++] = "- Hierarchical";
95 | slide.texts[slide.num_texts++] = " - Folders can be nested";
96 | slide.texts[slide.num_texts++] = " - Folders can be collapsed";
97 | slide.texts[slide.num_texts++] = "- Scrollable (no limit on items)";
98 | slide.texts[slide.num_texts++] = "- Dynamic (add/remove/modify items live)";
99 | slide.texts[slide.num_texts++] = "- Mouse/Keyboard/Gamepad support";
100 | }
101 | {
102 | DemoSlide& slide = data->slides[data->num_slides++];
103 | slide.texts[slide.num_texts++] = "Anything else?";
104 | slide.texts[slide.num_texts++] = "...";
105 | slide.texts[slide.num_texts++] = "You betcha!";
106 | }
107 | {
108 | DemoSlide& slide = data->slides[data->num_slides++];
109 | slide.texts[slide.num_texts++] = "Themes!";
110 | slide.texts[slide.num_texts++] = "- Only Classic looks decent";
111 | slide.texts[slide.num_texts++] = "- Please help me!";
112 | }
113 | {
114 | DemoSlide& slide = data->slides[data->num_slides++];
115 | slide.texts[slide.num_texts++] = "Alignment!";
116 | slide.texts[slide.num_texts++] = "- Left or right";
117 | }
118 | {
119 | DemoSlide& slide = data->slides[data->num_slides++];
120 | slide.texts[slide.num_texts++] = "Search!";
121 | slide.texts[slide.num_texts++] = "- Press backspace to start";
122 | slide.texts[slide.num_texts++] = "- ... and to stop";
123 | slide.texts[slide.num_texts++] = "- Fuzzy matching!";
124 | }
125 | {
126 | DemoSlide& slide = data->slides[data->num_slides++];
127 | slide.texts[slide.num_texts++] = "Item editors!";
128 | slide.texts[slide.num_texts++] = "- Bool items";
129 | slide.texts[slide.num_texts++] = "- 'Action array' items";
130 | slide.texts[slide.num_texts++] = "- Support for custom ones";
131 | }
132 | {
133 | DemoSlide& slide = data->slides[data->num_slides++];
134 | slide.texts[slide.num_texts++] = "Presets!";
135 | slide.texts[slide.num_texts++] = "- Activate one item...";
136 | slide.texts[slide.num_texts++] = "- ... and affect multiple!";
137 | }
138 | {
139 | DemoSlide& slide = data->slides[data->num_slides++];
140 | slide.texts[slide.num_texts++] = "Hotkeys!";
141 | slide.texts[slide.num_texts++] = "- Bind input to specific items";
142 | slide.texts[slide.num_texts++] = "- Activate when menu is closed";
143 | }
144 | {
145 | DemoSlide& slide = data->slides[data->num_slides++];
146 | slide.texts[slide.num_texts++] = "Default and overriden values!";
147 | slide.texts[slide.num_texts++] = "- See highlighted colors.";
148 | }
149 | {
150 | DemoSlide& slide = data->slides[data->num_slides++];
151 | slide.texts[slide.num_texts++] = "Save & Load!";
152 | slide.texts[slide.num_texts++] = "- Remembers state.";
153 | slide.texts[slide.num_texts++] = "- Items & Folders.";
154 | }
155 | {
156 | DemoSlide& slide = data->slides[data->num_slides++];
157 | slide.texts[slide.num_texts++] = "That's it!";
158 | slide.texts[slide.num_texts++] = "- I'm open to...";
159 | slide.texts[slide.num_texts++] = "- ...suggestions.";
160 | slide.texts[slide.num_texts++] = "- ...feature requests.";
161 | slide.texts[slide.num_texts++] = "- ...bug reports.";
162 | slide.texts[slide.num_texts++] = "- @srekel";
163 | slide.texts[slide.num_texts++] = "- srekel@gmail.com";
164 | slide.texts[slide.num_texts++] = "- https://github.com/Srekel/the-debuginator/";
165 | }
166 | }
167 |
168 | DemoData* demo_init(GuiHandle gui, TheDebuginator* debuginator) {
169 | memset(&s_demo_data, 0, sizeof(s_demo_data));
170 | s_demo_data.gui = gui;
171 | s_demo_data.debuginator = debuginator;
172 | s_demo_data.current_slide = -1;
173 | s_demo_data.font_handle = gui_register_font_template(gui, "LiberationMono-Regular.ttf", 24);
174 | debug_menu_setup(debuginator, &s_demo_data);
175 | presentation_setup(&s_demo_data);
176 | demo_trigger_next(&s_demo_data);
177 |
178 | return &s_demo_data;
179 | }
180 |
181 | void demo_update(DemoData* data, float dt, Vector2 offset) {
182 | if (data->current_slide == -1) {
183 | return;
184 | }
185 |
186 | Vector2 pos = offset;
187 | pos.x += 50;
188 | DemoSlide& slide = data->slides[data->current_slide];
189 | for (int i=0; i < slide.num_texts_visible; ++i) {
190 | float& anim_time = slide.anim_times[i];
191 | anim_time += dt * 3;
192 | if (anim_time > 1.f) {
193 | anim_time = 1.f;
194 | }
195 |
196 | pos.x = 150.f + (-150.f + pos.x) * anim_time;
197 | Color color(150, 50, 150, 255);
198 | // unsigned char base_color = slide.num_texts_visible == slide.num_texts ? 100 : 50;
199 | unsigned char base_color = 50;
200 | color.a = (unsigned char)(anim_time * color.a);
201 | color.r = (unsigned char)(base_color + anim_time * color.r);
202 | color.g = (unsigned char)(base_color + anim_time * color.g);
203 | color.b = (unsigned char)(base_color + anim_time * color.b);
204 | gui_draw_text(data->gui, slide.texts[i], pos, data->font_handle, color);
205 | pos.y += 50;
206 | }
207 |
208 | unsigned char progress_bar_brightness = slide.num_texts_visible == slide.num_texts ? 250 : 150;
209 | Color progress_bar_background_color(100, 0, 100, 200);
210 | Color progress_bar_color(progress_bar_brightness, 0, progress_bar_brightness, progress_bar_brightness);
211 | Vector2 progress_bar_pos(offset.x + 50, offset.y + 20);
212 | Vector2 progress_bar_background_size(350, 5);
213 | Vector2 progress_bar_size(350.f * slide.num_texts_visible / slide.num_texts, 5);
214 | gui_draw_rect_filled(data->gui, progress_bar_pos, progress_bar_background_size, progress_bar_background_color);
215 | gui_draw_rect_filled(data->gui, progress_bar_pos, progress_bar_size, progress_bar_color);
216 | }
217 |
--------------------------------------------------------------------------------
/tests/sdl/demo.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "gui.h"
6 |
7 | struct TheDebuginator;
8 |
9 | struct DemoSlide {
10 | const char* texts[8];
11 | float anim_times[8];
12 | int num_texts;
13 | int num_texts_visible;
14 | };
15 |
16 | struct DemoData {
17 | GuiHandle gui;
18 | TheDebuginator* debuginator;
19 | FontTemplateHandle font_handle;
20 |
21 | DemoSlide slides[32];
22 | int num_slides;
23 | int current_slide;
24 | };
25 |
26 |
27 | DemoData* demo_init(GuiHandle gui, TheDebuginator* debuginator);
28 | void demo_update(DemoData* demo_data, float dt, Vector2 offset);
29 | void demo_trigger_next(DemoData* demo_data);
30 |
--------------------------------------------------------------------------------
/tests/sdl/game.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include "../../the_debuginator.h"
3 |
4 | //#include
5 | #include
6 | #include
7 |
8 | #include "game.h"
9 |
10 | static void on_colorpicker(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
11 | (void)app_userdata;
12 | (void)value;
13 | (void)value_title;
14 | GameData* data = (GameData*)item->user_data;
15 | data->background_color = *(DebuginatorColor*)(value);
16 | }
17 |
18 | static void on_box_action(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
19 | (void)app_userdata;
20 | (void)value;
21 | GameBox* box = (GameBox*)item->user_data;
22 | if (strcmp(value_title, "Hide") == 0) {
23 | box->color.a = 0;
24 | }
25 | else if (strcmp(value_title, "Show") == 0) {
26 | box->color.a = box->alpha;
27 | }
28 | else if (strcmp(value_title, "Speed up") == 0) {
29 | box->velocity.x *= 2;
30 | box->velocity.y *= 2;
31 | }
32 | else if (strcmp(value_title, "Slow down") == 0) {
33 | box->velocity.x *= 0.5f;
34 | box->velocity.y *= 0.5f;
35 | }
36 | }
37 |
38 | #pragma warning(suppress: 4505) // unreferenced local function
39 | static void on_boxes_activated(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
40 | (void)app_userdata;
41 | (void)value;
42 | GameData* data = (GameData*)item->user_data;
43 | if (strcmp(value_title, "Add box") == 0 && data->boxes_n < 256) {
44 | GameBox* box = &data->boxes[data->boxes_n++];
45 | box->randomize();
46 |
47 | // Add item for box
48 | char folder[64] = { 0 };
49 | sprintf_s(folder, 64, "Game/Boxes/Box %02d", data->boxes_n);
50 | static const char* box_action_titles[5] = { "Hide", "Show", "Speed up", "Slow down" };
51 | debuginator_create_array_item(data->debuginator, NULL, folder,
52 | "Change box properties.", on_box_action, box,
53 | box_action_titles, NULL, 4, 0);
54 | debuginator_set_edit_type(data->debuginator, folder, DEBUGINATOR_EditTypeActionArray);
55 | }
56 | else if (strcmp(value_title, "Clear all boxes") == 0 && data->boxes_n < 256) {
57 | data->boxes_n = 0;
58 |
59 | debuginator_remove_item_by_path(data->debuginator, "Game/Boxes");
60 | }
61 |
62 | sprintf_s(data->box_string, "Box count: %d", data->boxes_n);
63 | }
64 |
65 | // static void on_number_changed(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
66 | // (void)item, value_title, app_userdata;
67 | // float fvalue = *(float*)value;
68 | // GameData* data = (GameData*)item->user_data;
69 | // data->background_color.r = (unsigned char)fvalue;
70 | // }
71 |
72 | static void debug_menu_setup(TheDebuginator* debuginator, GameData* data) {
73 | (void)data;
74 | {
75 | static const char* string_titles[5] = { "String A", "String B", "String C", "String D", "String E" };
76 | debuginator_create_array_item(debuginator, NULL, "SDL Demo/Edit types/String list",
77 | "Example of an item having multiple strings to choose from.", NULL, NULL,
78 | string_titles, NULL, 5, 0);
79 | }
80 |
81 | {
82 | DebuginatorColor start = { 200, 0, 200, 200 };
83 | debuginator_create_colorpicker_item(debuginator, "SDL Demo/Edit types/Colorpicker",
84 | "Example of the colorpicker edit type.", on_colorpicker, data, &start);
85 | }
86 |
87 | debuginator_create_bool_item(debuginator, "SDL Demo/Draw boxes", "Whether to draw the animated boxes or not.", &data->draw_boxes);
88 |
89 | {
90 | sprintf_s(data->box_string, "Box count: %d", data->boxes_n);
91 | static const char* string_titles[3] = { "Clear all boxes", "Add box", data->box_string };
92 | debuginator_create_array_item(debuginator, NULL, "SDL Demo/Edit types/Box action list",
93 | "Various things to do with the demo boxes. Expand the item to see all the actions.", on_boxes_activated, data,
94 | string_titles, NULL, 3, 0);
95 | debuginator_set_edit_type(debuginator, "SDL Demo/Edit types/Box action list", DEBUGINATOR_EditTypeActionArray);
96 | }
97 | {
98 | char description_stack[256] = {};
99 | sprintf_s(description_stack, "Hello from the stack!");
100 | debuginator_create_bool_item(debuginator, "Test/Description/Stack allocated", description_stack, &data->mybool);
101 | char* description_heap = (char*)malloc(256);
102 | sprintf_s(description_heap, 256, "Hello from the heap!");
103 | debuginator_create_bool_item(debuginator, "Test/Description/Heap allocated", description_heap, &data->mybool);
104 | free(description_heap);
105 | }
106 | debuginator_create_bool_item(debuginator, "Test/Description/Empty", "", &data->mybool);
107 | debuginator_create_bool_item(debuginator, "Test/Description/NULL", "", &data->mybool);
108 | debuginator_create_bool_item(debuginator, "Test/Description/Long", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccc", &data->mybool);
109 | debuginator_create_bool_item(debuginator, "Test/Description/Newlines", "* A\n* B\n* C\n* D\n* E\n* F\n* G\n* H\n* I\n* J\n", &data->mybool);
110 | debuginator_create_bool_item(debuginator, "Test/LOL/XXZZ", "Change a bool.", &data->mybool);
111 | debuginator_create_bool_item(debuginator, "Test/LOL2/YY XX", "Change a bool.", &data->mybool);
112 | debuginator_create_bool_item(debuginator, "Test/LOL2/YY", "Change a bool.", &data->mybool);
113 | debuginator_create_bool_item(debuginator, "Test/LOL2/YYYY", "Change a bool.", &data->mybool);
114 | debuginator_create_bool_item(debuginator, "Test/LOL2/GameBooool0", "Change a bool.", &data->mybool);
115 | debuginator_create_bool_item(debuginator, "Test/YYY", NULL, &data->mybool);
116 |
117 |
118 | // debuginator_create_bool_item(debuginator, "SimpleBool 1", "Change a bool.", &data->mybool);
119 | // debuginator_create_bool_item(debuginator, "Folder/SimpleBool 2", "Change a bool.", &data->mybool);
120 | // debuginator_create_bool_item(debuginator, "Folder/SimpleBool 3", "Change a bool.", &data->mybool);
121 | // debuginator_create_bool_item(debuginator, "Folder/Subfolder with a long name ololololol/SimpleBool 4 with a really long long title", "Change a bool.", &data->mybool);
122 | // debuginator_create_bool_item(debuginator, "SDL Demo/Load test", "Change a bool.", &data->load_test);
123 |
124 | debuginator_create_folder_item(debuginator, NULL, "Folder 2");
125 | char folder[64] = { 0 };
126 | for (int i = 0; i < 5; i++) {
127 | for (int j = 0; j < 5; j++) {
128 | for (int l = 0; l < 5; l++) {
129 | sprintf_s(folder, 64, "Test/Hierarchy/Test%02d/Folder%02d/GameBool%02d", i, j, l);
130 | debuginator_create_bool_item(debuginator, folder, "Change a bool.", &data->gamebool);
131 | }
132 | }
133 | }
134 |
135 | // for (int i = 0; i < 1; i++) {
136 | // for (int j = 0; j < 1; j++) {
137 | // sprintf_s(folder, 64, "Game/Test%02d/GameBool%02d", i, j);
138 | // DebuginatorItem* item = debuginator_get_item(debuginator, NULL, folder, false);
139 | // debuginator_remove_item(debuginator, item);
140 | // }
141 | // }
142 |
143 | DebuginatorItem* thu_item = debuginator_create_folder_item(debuginator, NULL, "Test/HierarchyUnsorted");
144 | thu_item->folder.is_sorted = false;
145 | debuginator_create_bool_item(debuginator, "Test/HierarchyUnsorted/First", "Change a bool.", &data->gamebool);
146 | debuginator_create_bool_item(debuginator, "Test/HierarchyUnsorted/Second", "Change a bool.", &data->gamebool);
147 | debuginator_create_bool_item(debuginator, "Test/HierarchyUnsorted/Folder/Third", "Change a bool.", &data->gamebool);
148 | debuginator_create_bool_item(debuginator, "Test/HierarchyUnsorted/Fourth", "Change a bool.", &data->gamebool);
149 | debuginator_create_bool_item(debuginator, "Test/HierarchyUnsorted/Fifth", "Change a bool.", &data->gamebool);
150 | debuginator_create_bool_item(debuginator, "Test/Hierarchy/1 First", "Change a bool.", &data->gamebool);
151 | debuginator_create_bool_item(debuginator, "Test/Hierarchy/2 Second", "Change a bool.", &data->gamebool);
152 | debuginator_create_bool_item(debuginator, "Test/Hierarchy/3 Folder/Third", "Actually fifth.", &data->gamebool);
153 | debuginator_create_bool_item(debuginator, "Test/Hierarchy/4 Fourth", "Change a bool.", &data->gamebool);
154 | debuginator_create_bool_item(debuginator, "Test/Hierarchy/5 Fifth", "Change a bool.", &data->gamebool);
155 | debuginator_create_bool_item(debuginator, "Test/Leaf/First/Enable", "Change a bool.", &data->gamebool);
156 | debuginator_create_bool_item(debuginator, "Test/Leaf/Second/Enable", "Change a bool.", &data->gamebool);
157 | debuginator_create_bool_item(debuginator, "Test/Leaf/Folder/Third/Enable", "Change a bool.", &data->gamebool);
158 | debuginator_create_bool_item(debuginator, "Test/Leaf/Folder/Fourth/Enable", "Change a bool.", &data->gamebool);
159 | debuginator_create_bool_item(debuginator, "Test/Leaf/Fifth/Enable", "Change a bool.", &data->gamebool);
160 |
161 | debuginator_set_collapsed(debuginator, debuginator_get_item(debuginator, NULL, "Test", NULL), true);
162 | }
163 |
164 | static GameData s_game_data;
165 |
166 | GameData* game_init(GuiHandle gui, TheDebuginator* debuginator) {
167 | memset(&s_game_data, 0, sizeof(s_game_data));
168 | s_game_data.window_size = gui_get_window_size(gui);
169 | s_game_data.gui = gui;
170 | s_game_data.debuginator = debuginator;
171 | debug_menu_setup(debuginator, &s_game_data);
172 |
173 | return &s_game_data;
174 | }
175 |
176 | void game_update(GameData* game_data, float dt) {
177 |
178 | s_game_data.window_size = gui_get_window_size(game_data->gui);
179 | debuginator_set_screen_resolution(game_data->debuginator, (int)s_game_data.window_size.x, (int)s_game_data.window_size.y);
180 |
181 | // bouncing boxes
182 | if (game_data->draw_boxes) {
183 | for (size_t box_i = 0; box_i < game_data->boxes_n; box_i++) {
184 | GameBox* box = &game_data->boxes[box_i];
185 | box->pos.x += box->velocity.x * (float)dt;
186 | box->pos.y += box->velocity.y * (float)dt;
187 | if (box->pos.x < 0 && box->velocity.x < 0 || box->pos.x + box->size.x > game_data->window_size.x && box->velocity.x > 0) {
188 | box->velocity.x *= -1;
189 | }
190 | if (box->pos.y - box->size.y < 0 && box->velocity.y < 0 || box->pos.y + box->size.y > game_data->window_size.y && box->velocity.y > 0) {
191 | box->velocity.y *= -1;
192 | }
193 | gui_draw_rect_filled(game_data->gui, box->pos, box->size, box->color);
194 | }
195 | }
196 | }
197 |
--------------------------------------------------------------------------------
/tests/sdl/game.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | #include "gui.h"
6 |
7 | struct TheDebuginator;
8 |
9 | struct GameBox {
10 | GameBox() {
11 | }
12 | void randomize() {
13 | pos.x = pos.y = 0;
14 | size.x = 50 + 100 * ((float)rand()) / RAND_MAX;
15 | size.y = 50 + 100 * ((float)rand()) / RAND_MAX;
16 | velocity.x = 5 + 150 * ((float)rand()) / RAND_MAX;
17 | velocity.y = 5 + 150 * ((float)rand()) / RAND_MAX;
18 | color.r = (unsigned char)(50 + 100 * ((float)rand()) / RAND_MAX);
19 | color.g = (unsigned char)(50 + 100 * ((float)rand()) / RAND_MAX);
20 | color.b = (unsigned char)(50 + 100 * ((float)rand()) / RAND_MAX);
21 | color.a = (unsigned char)(150 + 100 * ((float)rand()) / RAND_MAX);
22 | alpha = color.a;
23 | }
24 | Vector2 pos;
25 | Vector2 size;
26 | Vector2 velocity;
27 | Color color;
28 | unsigned char alpha;
29 | };
30 |
31 | struct GameData {
32 | GuiHandle gui;
33 | TheDebuginator* debuginator;
34 | bool mybool;
35 | bool gamebool;
36 | bool load_test;
37 | bool draw_boxes;
38 | char mystring[256];
39 | GameBox boxes[256];
40 | int boxes_n;
41 | char box_string[32];
42 | Vector2 window_size;
43 | DebuginatorColor background_color;
44 | };
45 |
46 |
47 | GameData* game_init(GuiHandle gui, TheDebuginator* debuginator);
48 | void game_update(GameData* game_data, float dt);
49 |
--------------------------------------------------------------------------------
/tests/sdl/gui.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #include
7 |
8 | #include "gui.h"
9 |
10 | struct FontTemplate {
11 | TTF_Font* font;
12 | //const char* font;
13 | //int size;
14 | };
15 |
16 | struct Gui {
17 | SDL_Window* window;
18 | SDL_Renderer* renderer;
19 | SDL_GameController* game_controllers[32];
20 |
21 | FontTemplate font_templates[8];
22 | int font_template_count;
23 |
24 | TextureHandle texture_handles[8];
25 | SDL_Texture* textures[8];
26 | int num_textures;
27 | };
28 |
29 | static Gui guis[1];
30 | static int gui_count = 0;
31 | static bool audio_enabled = false;
32 |
33 |
34 | GuiHandle gui_create_gui(int resx, int resy, const char* window_title, bool vsync_on) {
35 | if (gui_count > 0) {
36 | return (GuiHandle)nullptr;
37 | }
38 |
39 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER | SDL_INIT_AUDIO) == 0) {
40 | audio_enabled = true;
41 | initAudio();
42 | }
43 | else if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) != 0) {
44 | goto LABEL_error;
45 | }
46 |
47 | if (TTF_Init() != 0) {
48 | goto LABEL_error;
49 | }
50 |
51 | SDL_Window* window = SDL_CreateWindow(window_title,
52 | SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, resx, resy, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);
53 | if (window == NULL) {
54 | goto LABEL_error;
55 | }
56 |
57 | SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | (SDL_RENDERER_PRESENTVSYNC & (vsync_on ? 0xFFFFFFFF : 0)));
58 | if (renderer == NULL) {
59 | goto LABEL_error;
60 | }
61 |
62 | goto LABEL_init_success;
63 |
64 | LABEL_error:;
65 | if (audio_enabled) {
66 | endAudio();
67 | }
68 |
69 | SDL_Quit();
70 | return (GuiHandle)nullptr;
71 |
72 | LABEL_init_success:;
73 |
74 | SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
75 |
76 | Gui* gui = &guis[gui_count++];
77 | SDL_memset(gui, 0, sizeof(*gui));
78 | gui->renderer = renderer;
79 | gui->window = window;
80 |
81 | // Set up gamepads. Note: Doesn't handle adding while running.
82 | // If you don't have this file, make sure it gets copied from 3rdparty\SDL_GameControllerDB-master
83 | SDL_GameControllerAddMappingsFromFile("gamecontrollerdb.txt");
84 | SDL_JoystickEventState(SDL_ENABLE);
85 | int num_joysticks = SDL_NumJoysticks();
86 | for( int i=0; i < num_joysticks; i++ ) {
87 | if (SDL_IsGameController(i)) {
88 | gui->game_controllers[i] = SDL_GameControllerOpen(i);
89 | }
90 | }
91 |
92 | return (GuiHandle)gui;
93 | }
94 |
95 | void gui_destroy_gui(GuiHandle gui_handle) {
96 | Gui* gui = (Gui*)gui_handle;
97 |
98 | SDL_DestroyWindow(gui->window);
99 | SDL_Quit();
100 | }
101 |
102 | void gui_frame_begin(GuiHandle gui_handle) {
103 | Gui* gui = (Gui*)gui_handle;
104 | SDL_SetRenderDrawColor(gui->renderer, 30, 30, 30, 255);
105 | SDL_RenderClear(gui->renderer);
106 | }
107 |
108 | void gui_frame_end(GuiHandle gui_handle){
109 | Gui* gui = (Gui*)gui_handle;
110 | SDL_RenderPresent(gui->renderer);
111 | }
112 |
113 | TextureHandle gui_load_texture(GuiHandle gui_handle, const char* texture_filename) {
114 | Gui* gui = (Gui*)gui_handle;
115 | SDL_Texture* texture = IMG_LoadTexture(gui->renderer, texture_filename);
116 | // TODO Assert
117 | gui->textures[gui->num_textures] = texture;
118 | return (TextureHandle)gui->num_textures++;
119 | }
120 |
121 | void gui_draw_texture(GuiHandle gui_handle, TextureHandle handle, Vector2 position, Vector2 size) {
122 | Gui* gui = (Gui*)gui_handle;
123 | SDL_Texture* texture = gui->textures[handle];
124 | SDL_Rect texture_rect;
125 | texture_rect.x = (int)position.x;
126 | texture_rect.y = (int)position.y;
127 | texture_rect.w = (int)size.x;
128 | texture_rect.h = (int)size.y;
129 | if (texture_rect.w == 0) {
130 | int w, h;
131 | int res = SDL_QueryTexture(texture, NULL, NULL, &w, &h);
132 | (void)res;
133 | float ratio = (float)w / h;
134 | texture_rect.w = (int)(texture_rect.h * ratio);
135 | }
136 | if (texture_rect.h == 0) {
137 | int w, h;
138 | int res = SDL_QueryTexture(texture, NULL, NULL, &w, &h);
139 | (void)res;
140 | float ratio = (float)w / h;
141 | texture_rect.h = (int)(texture_rect.w / ratio);
142 | }
143 | SDL_RenderCopy(gui->renderer, texture, NULL, &texture_rect);
144 | }
145 |
146 | FontTemplateHandle gui_register_font_template(GuiHandle gui_handle, const char* font, int size) {
147 | TTF_Font* ttf_font = TTF_OpenFont(font, size);
148 | if (ttf_font == NULL) {
149 | return 0;
150 | }
151 |
152 | Gui* gui = (Gui*)gui_handle;
153 | FontTemplate* font_template = &gui->font_templates[gui->font_template_count++];
154 | font_template->font = ttf_font;
155 |
156 | return (FontTemplateHandle)font_template;
157 | }
158 |
159 | void gui_unregister_font_template(GuiHandle gui_handle, FontTemplateHandle font_handle) {
160 | (void)gui_handle;
161 | FontTemplate* font_template = (FontTemplate*)font_handle;
162 | TTF_CloseFont(font_template->font);
163 | font_template->font = 0;
164 | }
165 |
166 | void gui_draw_text(GuiHandle gui_handle, const char* text, Vector2 position, FontTemplateHandle font_handle, Color color) {
167 | Gui* gui = (Gui*)gui_handle;
168 | SDL_Color* text_color = (SDL_Color*)&color;
169 | FontTemplate* font_template = (FontTemplate*)font_handle;
170 | SDL_Surface* text_surface = TTF_RenderText_Blended(font_template->font, text, *text_color);
171 | if (text_surface == NULL) {
172 | // TODO Assert
173 | return;
174 | }
175 |
176 | SDL_Texture* text_texture = SDL_CreateTextureFromSurface(gui->renderer, text_surface);
177 | if (text_texture == NULL) {
178 | // TODO Assert
179 | return;
180 | }
181 |
182 | SDL_FreeSurface(text_surface);
183 |
184 | SDL_Rect rectangle;
185 | rectangle.x = (int)position.x;
186 | rectangle.y = (int)position.y;
187 | TTF_SizeText(font_template->font, text, &rectangle.w, &rectangle.h);
188 | rectangle.y -= rectangle.h / 2;
189 |
190 | SDL_SetRenderDrawColor(gui->renderer, 255, 255, 255, 255);
191 | SDL_RenderCopy(gui->renderer, text_texture, NULL, &rectangle);
192 |
193 | SDL_DestroyTexture(text_texture);
194 | }
195 |
196 | void gui_draw_rect_filled(GuiHandle gui_handle, Vector2 position, Vector2 size, Color color) {
197 | Gui* gui = (Gui*)gui_handle;
198 | SDL_Rect rect;
199 | rect.x = (int)position.x;
200 | rect.y = (int)position.y;
201 | rect.w = (int)size.x;
202 | rect.h = (int)size.y;
203 |
204 | SDL_SetRenderDrawColor(gui->renderer, color.r, color.g, color.b, color.a);
205 | SDL_RenderFillRect(gui->renderer, &rect);
206 | }
207 |
208 | void gui_word_wrap(GuiHandle gui_handle, const char* text, FontTemplateHandle font_handle, float max_width, int* row_count, int* row_lengths, int row_lengths_buffer_size) {
209 | (void)gui_handle;
210 | FontTemplate* font_template = (FontTemplate*)font_handle;
211 |
212 | const char* current_line = text;
213 | const char* current_word = text;
214 | const char* current_char = text;
215 | char line[256];
216 | while (*current_char != '\0') {
217 | bool found_newline = false;
218 | while (*current_char != '\0') {
219 | if (*current_char == ' ') {
220 | // We found a word end.
221 | // Include all trailing spaces in this word
222 | while (*current_char == ' ') {
223 | ++current_char;
224 | }
225 | break;
226 | }
227 |
228 | if (*current_char == '\n') {
229 | // We found a new line
230 | ++current_char;
231 | found_newline = true;
232 | break;
233 | }
234 |
235 | ++current_char;
236 | }
237 |
238 | memcpy(line, current_line, current_char - current_line);
239 | line[current_char - current_line] = '\0';
240 | int width;
241 | if (TTF_SizeText(font_template->font, line, &width, NULL) != 0) {
242 | break;
243 | }
244 |
245 | bool line_too_long = width >= max_width;
246 | if (line_too_long || found_newline) {
247 | bool word_longer_than_line = current_word == current_line;
248 | if (found_newline) {
249 | row_lengths[*row_count] = (int)(current_char - current_line - 1);
250 | ++*row_count;
251 | current_word = current_char;
252 | current_line = current_char;
253 | }
254 | else if (word_longer_than_line) {
255 | row_lengths[*row_count] = (int)(current_char - current_line);
256 | ++*row_count;
257 | current_word = current_char;
258 | current_line = current_char;
259 | }
260 | else {
261 | // Move current word to next line.
262 | row_lengths[*row_count] = (int)(current_word - current_line);
263 | ++*row_count;
264 |
265 | //current_word = current_char;
266 | current_line = current_word;
267 | }
268 |
269 | if (*row_count == row_lengths_buffer_size) {
270 | break;
271 | }
272 | }
273 | else {
274 | // Current word fit.
275 | current_word = current_char;
276 | }
277 | }
278 |
279 | if (*current_line != '\0') {
280 | // Add last line
281 | row_lengths[*row_count] = (int)(current_char - current_line);
282 | ++*row_count;
283 | }
284 | }
285 |
286 | Vector2 gui_text_size(GuiHandle gui_handle, const char* text, FontTemplateHandle font_handle) {
287 | Gui* gui = (Gui*)gui_handle;
288 | (void)gui;
289 | FontTemplate* font_template = (FontTemplate*)font_handle;
290 |
291 | if (text[0] == '\0') {
292 | return Vector2(0, 0);
293 | }
294 |
295 | int x, y;
296 | TTF_SizeText(font_template->font, text, &x, &y);
297 | Vector2 out_text_size((float)x, (float)y);
298 | return out_text_size;
299 | }
300 |
301 | Vector2 gui_get_window_size(GuiHandle gui_handle) {
302 | Gui* gui = (Gui*)gui_handle;
303 | int w, h;
304 | SDL_GetWindowSize(gui->window, &w, &h);
305 | return Vector2((float)w, (float)h);
306 | }
307 |
308 | SDL_GameController** gui_get_controllers(GuiHandle gui_handle) {
309 | Gui* gui = (Gui*)gui_handle;
310 | return gui->game_controllers;
311 | }
312 |
313 | void gui_play_sound(DebuginatorSoundEvent event) {
314 | switch (event) {
315 | case DEBUGINATOR_SoundEventEnter: {
316 | playSound("bong_001.wav", SDL_MIX_MAXVOLUME / 16);
317 | }
318 | break;
319 | case DEBUGINATOR_SoundEventActivate: {
320 | playSound("select_007.wav", SDL_MIX_MAXVOLUME / 4);
321 | }
322 | break;
323 | case DEBUGINATOR_SoundEventCollapse: {
324 | playSound("pluck_001.wav", SDL_MIX_MAXVOLUME / 6);
325 | }
326 | break;
327 | case DEBUGINATOR_SoundEventExpand: {
328 | playSound("pluck_002.wav", SDL_MIX_MAXVOLUME / 6);
329 | }
330 | break;
331 |
332 | }
333 | }
--------------------------------------------------------------------------------
/tests/sdl/gui.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "../../the_debuginator.h"
6 |
7 | typedef intptr_t GuiHandle;
8 | typedef intptr_t FontTemplateHandle;
9 | typedef intptr_t TextureHandle;
10 |
11 | struct Vector2 {
12 | Vector2() : x(0), y(0) {}
13 | Vector2(float x, float y) : x(x), y(y) {}
14 | float x;
15 | float y;
16 | };
17 |
18 | struct Color {
19 | Color() : r(0), g(0), b(0), a(0) {}
20 | Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a) : r(r), g(g), b(b), a(a) {}
21 | unsigned char r;
22 | unsigned char g;
23 | unsigned char b;
24 | unsigned char a;
25 | };
26 |
27 | GuiHandle gui_create_gui(int resx, int resy, const char* window_title, bool vsync_on);
28 | void gui_destroy_gui(GuiHandle gui_handle);
29 |
30 | void gui_frame_begin(GuiHandle gui_hande);
31 | void gui_frame_end(GuiHandle gui_hande);
32 |
33 | TextureHandle gui_load_texture(GuiHandle gui, const char* texture_filename);
34 | void gui_draw_texture(GuiHandle gui_handle, TextureHandle handle, Vector2 position, Vector2 size);
35 |
36 | FontTemplateHandle gui_register_font_template(GuiHandle gui_handle, const char* font, int size);
37 | void gui_unregister_font_template(GuiHandle gui_handle, FontTemplateHandle font_handle);
38 |
39 | void gui_draw_text(GuiHandle gui_handle, const char* text, Vector2 position, FontTemplateHandle font, Color color);
40 | void gui_draw_rect_filled(GuiHandle gui_handle, Vector2 position, Vector2 size, Color color);
41 |
42 | void gui_word_wrap(GuiHandle gui_handle, const char* text, FontTemplateHandle font_handle, float max_width, int* row_count, int* row_lengths, int row_lengths_buffer_size);
43 | Vector2 gui_text_size(GuiHandle gui_handle, const char* text, FontTemplateHandle font_handle);
44 |
45 | Vector2 gui_get_window_size(GuiHandle gui_handle);
46 | SDL_GameController** gui_get_controllers(GuiHandle gui_handle);
47 |
48 | void gui_play_sound(DebuginatorSoundEvent event);
49 |
--------------------------------------------------------------------------------
/tests/sdl/main.cpp:
--------------------------------------------------------------------------------
1 |
2 | #include
3 |
4 | static const int WIDTH = 500;
5 |
6 | static void unittest_debuginator_assert(bool test) {
7 | if (!test) {
8 | }
9 | assert(test);
10 | //DebugBreak();
11 | }
12 |
13 | #define DEBUGINATOR_assert unittest_debuginator_assert
14 | #define DEBUGINATOR_static_assert unittest_debuginator_assert
15 | #define ASSERT unittest_debuginator_assert
16 | #define DEBUGINATOR_IMPLEMENTATION
17 | #include "../../the_debuginator.h"
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "gui.h"
25 | #include "game.h"
26 | #include "demo.h"
27 |
28 | enum FontTemplate {
29 | FONT_DemoHeader,
30 | FONT_ItemTitle,
31 | FONT_ItemDescription,
32 | FONT_Count
33 | };
34 |
35 | static FontTemplateHandle s_fonts[16];
36 |
37 | static bool theme_setup(GuiHandle gui) {
38 | memset(s_fonts, 0, sizeof(*s_fonts));
39 | s_fonts[FONT_DemoHeader] = gui_register_font_template(gui, "LiberationMono-Bold.ttf", 72);
40 | s_fonts[FONT_ItemTitle] = gui_register_font_template(gui, "LiberationMono-Regular.ttf", 18);
41 | s_fonts[FONT_ItemDescription] = gui_register_font_template(gui, "LiberationSerif-Regular.ttf", 18);
42 |
43 | for (size_t i = 0; i < FONT_Count; i++) {
44 | if (s_fonts[i] == 0) {
45 | return false;
46 | }
47 | }
48 |
49 | return true;
50 | }
51 |
52 | void draw_text(const char* text, DebuginatorVector2* position, DebuginatorColor* color, DebuginatorFont* font, void* userdata) {
53 | GuiHandle gui = (GuiHandle)userdata;
54 | int color_index = font->draw_type == DEBUGINATOR_ItemDescription ? (int)FONT_ItemDescription : (int)FONT_ItemTitle;
55 | gui_draw_text(gui, text, *(Vector2*)position, s_fonts[color_index], *(Color*)color);
56 | }
57 |
58 | void draw_rect(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorColor* color, void* userdata) {
59 | gui_draw_rect_filled((GuiHandle)userdata, *(Vector2*)position, *(Vector2*)size, *(Color*)color);
60 | }
61 |
62 | void draw_image(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorImageHandle handle, void* userdata) {
63 | gui_draw_texture((GuiHandle)userdata, handle.h.ull_value, *(Vector2*)position, *(Vector2*)size);
64 | }
65 |
66 | void word_wrap(const char* text, DebuginatorFont* font, float max_width, int* row_count, int* row_lengths, int row_lengths_buffer_size, void* app_userdata) {
67 | int color_index = font->draw_type == DEBUGINATOR_ItemDescription ? (int)FONT_ItemDescription : (int)FONT_ItemTitle;
68 | gui_word_wrap((GuiHandle)app_userdata, text, s_fonts[color_index], max_width, row_count, row_lengths, row_lengths_buffer_size);
69 | }
70 |
71 | DebuginatorVector2 text_size(const char* text, DebuginatorFont* font, void* userdata) {
72 | int color_index = font->draw_type == DEBUGINATOR_ItemDescription ? (int)FONT_ItemDescription : (int)FONT_ItemTitle;
73 | Vector2 text_size = gui_text_size((GuiHandle)userdata, text, s_fonts[color_index]);
74 | return *(DebuginatorVector2*)&text_size;
75 | }
76 |
77 | void log(const char* text, void* userdata) {
78 | (void)userdata;
79 | printf("[Debuginator] %s\n", text);
80 | }
81 |
82 | void play_sound(DebuginatorSoundEvent event, void* userdata) {
83 | (void)userdata;
84 | gui_play_sound(event);
85 | }
86 |
87 | struct SaveData {
88 | char* buffer;
89 | int buffer_size;
90 | int buffer_capacity;
91 | };
92 |
93 | bool save_item(const char* key, const char* value, void* userdata) {
94 | SaveData* save_data = (SaveData*)userdata;
95 | if (save_data->buffer_capacity - save_data->buffer_size < 512) {
96 | return false;
97 | }
98 |
99 | int chars = sprintf_s(save_data->buffer + save_data->buffer_size, save_data->buffer_capacity - save_data->buffer_size, "%s=%s\n", key, value);
100 | save_data->buffer_size += chars;
101 | return true;
102 | }
103 |
104 | void save(TheDebuginator* debuginator) {
105 | SaveData save_data;
106 | save_data.buffer = NULL;
107 | save_data.buffer_size = 0;
108 | save_data.buffer_capacity = 1024;
109 |
110 | while (true) {
111 | save_data.buffer = (char*)malloc(save_data.buffer_capacity);
112 | memset(save_data.buffer, 0, save_data.buffer_capacity);
113 | bool saved = debuginator_save(debuginator, save_item, &save_data);
114 | if (saved) {
115 | break;
116 | }
117 |
118 | save_data.buffer_size = 0;
119 | save_data.buffer_capacity *= 16;
120 | free(save_data.buffer);
121 | }
122 |
123 | FILE* file = NULL;
124 | int error = fopen_s(&file, "DebuginatorConfig.txt", "w");
125 | if (file == NULL || error < 0) {
126 | return;
127 | }
128 |
129 | fputs(save_data.buffer, file);
130 | fclose(file);
131 | free(save_data.buffer);
132 | }
133 |
134 | bool load(TheDebuginator* debuginator, char* loaded_data_buffer, int loaded_buffer_size) {
135 | FILE* file = NULL;
136 | int error = fopen_s(&file, "DebuginatorConfig.txt", "r");
137 | if (file == NULL || error < 0) {
138 | return true;
139 | }
140 |
141 | bool result = true;
142 | char load_buffer[1024] = { 0 };
143 | fread_s(load_buffer, 1024, 1, 1023, file);
144 | const char* data = load_buffer;
145 | while (*data != '\0') {
146 | if (loaded_buffer_size < 512) {
147 | result = false;
148 | break;
149 | }
150 |
151 | const char* key = data;
152 | const char* value = NULL;
153 | const char* loaded_data_buffer_key = NULL;
154 | const char* loaded_data_buffer_value = NULL;
155 | while (*data++ != '\0') {
156 | if (*data == '=') {
157 | memcpy(loaded_data_buffer, key, data - key);
158 | loaded_data_buffer[data - key] = 0;
159 | loaded_data_buffer_key = loaded_data_buffer;
160 | loaded_data_buffer += data - key + 1;
161 | loaded_buffer_size -= (int)(data - key + 1);
162 | value = (++data);
163 | }
164 |
165 | if (*data == '\n' && value != NULL) {
166 | memcpy(loaded_data_buffer, value, data - value);
167 | loaded_data_buffer[data - value] = 0;
168 | loaded_data_buffer_value = loaded_data_buffer;
169 | loaded_data_buffer += data - value + 1;
170 | loaded_buffer_size -= (int)(data - value + 1);
171 | // Debuginator needs to own this
172 | const char* value_owned = debuginator_copy_string(debuginator, loaded_data_buffer_value, 0);
173 | debuginator_load_item(debuginator, loaded_data_buffer_key, value_owned);
174 | ++data;
175 | break;
176 | }
177 | }
178 | }
179 |
180 | fclose(file);
181 | return result;
182 | }
183 |
184 | bool handle_debuginator_keyboard_input_event(SDL_Event* event, TheDebuginator* debuginator, DemoData* demodata) {
185 | if (event->type == SDL_MOUSEBUTTONDOWN) {
186 | DebuginatorItem* hot_mouse_item = debuginator_get_item_at_mouse_cursor(debuginator, NULL);
187 | if (hot_mouse_item == NULL) {
188 | demo_trigger_next(demodata);
189 | }
190 | }
191 |
192 | if (!debuginator_is_open(debuginator)) {
193 | if (event->type == SDL_TEXTINPUT) {
194 | int text_length = (int)strlen(event->text.text);
195 | if (text_length > 0) {
196 | char key[] = { event->text.text[0], 0 };
197 | debuginator_activate_hot_key(debuginator, key);
198 | }
199 |
200 | return true;
201 | }
202 |
203 | if (event->type == SDL_KEYDOWN) {
204 | if (event->key.keysym.sym == SDLK_RIGHT || event->key.keysym.scancode == SDL_SCANCODE_GRAVE) {
205 | debuginator_set_open(debuginator, true);
206 | return true;
207 | }
208 | }
209 |
210 | return false;
211 | }
212 |
213 | int hot_item_index;
214 | DebuginatorItem* hot_item = debuginator_get_hot_item(debuginator, &hot_item_index);
215 | switch (event->type) {
216 | case SDL_KEYDOWN:
217 | {
218 | if (event->key.keysym.scancode == SDL_SCANCODE_LCTRL || event->key.keysym.scancode == SDL_SCANCODE_RCTRL) {
219 | return true;
220 | }
221 |
222 | if (event->key.keysym.sym == SDLK_UP) {
223 | debuginator_reset_scrolling(debuginator);
224 | bool long_move = (event->key.keysym.mod & SDLK_LCTRL) > 0;
225 | debuginator_move_to_prev_leaf(debuginator, long_move);
226 | return true;
227 | }
228 | else if (event->key.keysym.sym == SDLK_DOWN) {
229 | debuginator_reset_scrolling(debuginator);
230 | bool long_move = (event->key.keysym.mod & SDLK_LCTRL) > 0;
231 | debuginator_move_to_next_leaf(debuginator, long_move);
232 | return true;
233 | }
234 | else if (event->key.keysym.sym == SDLK_LEFT || event->key.keysym.sym == SDLK_ESCAPE || event->key.keysym.scancode == SDL_SCANCODE_GRAVE) {
235 | debuginator_reset_scrolling(debuginator);
236 | if (debuginator->is_open && (debuginator_is_folder(hot_item) || !hot_item->leaf.is_expanded)) {
237 | debuginator_set_open(debuginator, false);
238 | save(debuginator);
239 | return true;
240 | }
241 | else if (!debuginator_is_folder(hot_item) && hot_item->leaf.is_expanded) {
242 | debuginator_move_to_parent(debuginator);
243 | return true;
244 | }
245 | }
246 | else if (event->key.keysym.sym == SDLK_RIGHT) {
247 | debuginator_reset_scrolling(debuginator);
248 | if (debuginator_is_folder(hot_item)) {
249 | debuginator_set_collapsed(debuginator, hot_item, !debuginator_is_collapsed(hot_item));
250 | return true;
251 | }
252 | else {
253 | bool direct_activate = (event->key.keysym.mod & SDLK_LCTRL) > 0;
254 | debuginator_move_to_child(debuginator, direct_activate);
255 | return true;
256 | }
257 | }
258 | else if (event->key.keysym.sym == SDLK_BACKSPACE) {
259 | if (debuginator->filter_length > 0) {
260 | char filter[64] = { 0 };
261 | strcpy_s(filter, 64, debuginator->filter);
262 | filter[--debuginator->filter_length] = '\0';
263 | debuginator_update_filter(debuginator, filter);
264 | //debuginator->filter[--debuginator->filter_length] = '\0';
265 | }
266 | else if (debuginator->filter_enabled) {
267 | debuginator_set_filtering_enabled(debuginator, false);
268 | }
269 | else {
270 | debuginator_set_filtering_enabled(debuginator, true);
271 | }
272 | }
273 | else if (event->key.keysym.sym >= 'a' && event->key.keysym.sym <= 'z') {
274 | int hot_mouse_item_index;
275 | DebuginatorItem* hot_mouse_item = debuginator_get_item_at_mouse_cursor(debuginator, &hot_mouse_item_index);
276 | if (hot_mouse_item != NULL) {
277 | hot_item = hot_mouse_item;
278 | hot_item_index = hot_mouse_item_index;
279 | }
280 |
281 | int buffer_size = 256;
282 | char path[256];
283 | debuginator_get_path(debuginator, hot_item, path, &buffer_size);
284 | ASSERT(buffer_size == 256);
285 | char key[] = { (char)event->key.keysym.sym, 0 };
286 |
287 | DebuginatorItem* prev_hot_key_item = debuginator_get_first_assigned_hot_key_item(debuginator, key);
288 | if ( prev_hot_key_item == hot_item ) {
289 | // Key was already assigned to this item, toggle it off
290 | debuginator_unassign_hot_key(debuginator, key);
291 | break;
292 | }
293 |
294 | bool multi_add_key_held = SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL);
295 | if (prev_hot_key_item && !multi_add_key_held) {
296 | // Item was already assigned to something and user just wants the new one assigned,
297 | // so unassign the old one first.
298 | debuginator_unassign_hot_key(debuginator, key);
299 | }
300 |
301 | debuginator_assign_hot_key(debuginator, key, path, hot_item_index, NULL);
302 | }
303 | break;
304 | }
305 | case SDL_TEXTINPUT:
306 | {
307 | int new_text_length = (int)strlen(event->text.text);
308 | if (debuginator->filter_enabled) {
309 | if (debuginator->filter_length + new_text_length >= sizeof(debuginator->filter)) {
310 | break;
311 | }
312 |
313 | char filter[64] = { 0 };
314 | ASSERT(sizeof(filter) >= sizeof(debuginator->filter));
315 | strcpy_s(filter, sizeof(debuginator->filter), debuginator->filter);
316 | strcat_s(filter, sizeof(debuginator->filter), event->text.text);
317 | // if (SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL);)
318 | debuginator->filter_length = (int)strlen(filter);
319 | debuginator_update_filter(debuginator, filter);
320 | }
321 | break;
322 | }
323 | case SDL_MOUSEMOTION: {
324 | DebuginatorVector2 mouse_cursor_pos = { (float)event->motion.x, (float)event->motion.y };
325 | debuginator_set_mouse_cursor_pos(debuginator, &mouse_cursor_pos);
326 |
327 | break;
328 | }
329 | case SDL_MOUSEWHEEL: {
330 | debuginator_apply_scroll(debuginator, event->wheel.y * debuginator->item_height * 1);
331 |
332 | break;
333 | }
334 | case SDL_MOUSEBUTTONDOWN: {
335 | DebuginatorVector2 mouse_cursor_pos = { (float)event->button.x, (float)event->button.y };
336 | debuginator_set_mouse_cursor_pos(debuginator, &mouse_cursor_pos);
337 | if (event->button.button == SDL_BUTTON_LEFT && event->button.state == SDL_PRESSED) {
338 | debuginator_activate_item_at_mouse_cursor(debuginator);
339 | }
340 | else if (event->button.button == SDL_BUTTON_RIGHT && event->button.state == SDL_PRESSED) {
341 | debuginator_expand_item_at_mouse_cursor(debuginator, DEBUGINATOR_Toggle);
342 | }
343 |
344 | break;
345 | }
346 | case SDL_WINDOWEVENT: {
347 | if (event->window.event == SDL_WINDOWEVENT_LEAVE) {
348 | DebuginatorVector2 mouse_cursor_pos = { -1.f, -1.f };
349 | debuginator_set_mouse_cursor_pos(debuginator, &mouse_cursor_pos);
350 | }
351 |
352 | break;
353 | }
354 | }
355 |
356 |
357 | return false;
358 | }
359 |
360 | bool handle_debuginator_gamepad_input_event(SDL_Event* event, TheDebuginator* debuginator, SDL_GameControllerButton& current_button, double& time_since_button_pressed, float& scroll_speed) {
361 | switch (event->type) {
362 | case SDL_CONTROLLERBUTTONDOWN:
363 | {
364 | SDL_ControllerButtonEvent& button_ev = event->cbutton;
365 | current_button = (SDL_GameControllerButton)button_ev.button;
366 | time_since_button_pressed = 0;
367 |
368 | debuginator_reset_scrolling(debuginator);
369 |
370 | if (button_ev.button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
371 | bool long_move = (event->key.keysym.mod & SDLK_LCTRL) > 0;
372 | debuginator_move_to_prev_leaf(debuginator, long_move);
373 | return true;
374 | }
375 | else if (button_ev.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
376 | bool long_move = (event->key.keysym.mod & SDLK_LCTRL) > 0;
377 | debuginator_move_to_next_leaf(debuginator, long_move);
378 | return true;
379 | }
380 | else if (current_button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
381 | bool long_move = true;
382 | debuginator_move_to_prev_leaf(debuginator, long_move);
383 | return true;
384 | }
385 | else if (current_button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
386 | bool long_move = true;
387 | debuginator_move_to_next_leaf(debuginator, long_move);
388 | return true;
389 | }
390 | else if (button_ev.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT || button_ev.button == SDL_CONTROLLER_BUTTON_BACK) {
391 | if (debuginator->is_open && !debuginator->hot_item->leaf.is_expanded) {
392 | debuginator_set_open(debuginator, false);
393 | save(debuginator);
394 | return true;
395 | }
396 | else if (!debuginator->hot_item->is_folder && debuginator->hot_item->leaf.is_expanded) {
397 | debuginator_move_to_parent(debuginator);
398 | return true;
399 | }
400 | }
401 | else if (button_ev.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) {
402 | if (!debuginator->is_open) {
403 | debuginator_set_open(debuginator, true);
404 | return true;
405 | }
406 | else {
407 | bool direct_activate = (event->key.keysym.mod & SDLK_LCTRL) > 0;
408 | debuginator_move_to_child(debuginator, direct_activate);
409 | return true;
410 | }
411 | }
412 | else if (button_ev.button == SDL_CONTROLLER_BUTTON_A) {
413 | bool direct_activate = true;
414 | debuginator_move_to_child(debuginator, direct_activate);
415 | return true;
416 | }
417 |
418 | }
419 | break;
420 | case SDL_CONTROLLERBUTTONUP:
421 | {
422 | current_button = SDL_CONTROLLER_BUTTON_INVALID;
423 | //in_repeat_mode = false;
424 | }
425 | break;
426 | case SDL_CONTROLLERAXISMOTION:
427 | {
428 | SDL_ControllerAxisEvent& motion_ev = event->caxis;
429 | if (motion_ev.axis == SDL_CONTROLLER_AXIS_LEFTY) {
430 | scroll_speed = 0;
431 | if (motion_ev.value < -5000 || motion_ev.value > 5000) {
432 | scroll_speed = (float)(-3000 * (motion_ev.value / 32767.0) * (motion_ev.value / 32767.0) * (motion_ev.value / 32767.0));
433 | }
434 | }
435 | }
436 | break;
437 | }
438 |
439 | return false;
440 | }
441 |
442 | void handle_debuginator_gamepad_input(TheDebuginator* debuginator, SDL_GameControllerButton current_button, double& time_since_button_pressed) {
443 | if (current_button == SDL_CONTROLLER_BUTTON_INVALID) {
444 | return;
445 | }
446 |
447 | if (time_since_button_pressed < 0.3) {
448 | return;
449 | }
450 |
451 | time_since_button_pressed = 0.25;
452 | if (current_button == SDL_CONTROLLER_BUTTON_DPAD_UP) {
453 | bool long_move = false;
454 | debuginator_move_to_prev_leaf(debuginator, long_move);
455 | return;
456 | }
457 | else if (current_button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) {
458 | bool long_move = false;
459 | debuginator_move_to_next_leaf(debuginator, long_move);
460 | return;
461 | }
462 | else if (current_button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER) {
463 | bool long_move = true;
464 | debuginator_move_to_prev_leaf(debuginator, long_move);
465 | return;
466 | }
467 | else if (current_button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER) {
468 | bool long_move = true;
469 | debuginator_move_to_next_leaf(debuginator, long_move);
470 | return;
471 | }
472 | }
473 | void handle_debuginator_gamepad_input_immediate(TheDebuginator* debuginator, GuiHandle gui) {
474 | SDL_GameController** controller = gui_get_controllers(gui);
475 | while(*controller) {
476 | int axis_value = SDL_GameControllerGetAxis(*controller, SDL_CONTROLLER_AXIS_RIGHTY);
477 | if (axis_value * axis_value > 8000 * 8000) {
478 | float change = 0.1f * (axis_value / 32767.0f) * (axis_value / 32767.0f) * (axis_value / 32767.0f);
479 | DebuginatorItem* hot_item = debuginator_get_hot_item(debuginator, NULL);
480 | debuginator_modify_value(debuginator, hot_item, 0, change, false);
481 | }
482 |
483 | ++controller;
484 | }
485 | }
486 |
487 | int main(int argc, char **argv)
488 | {
489 | (void)(argc, argv);
490 |
491 | int res_x = 1280;
492 | int res_y = 720;
493 | bool vsync_on = true;
494 | GuiHandle gui = gui_create_gui(res_x, res_y, "The Debuginator - SDL Demo", vsync_on);
495 | if (gui == 0) {
496 | return 1;
497 | }
498 |
499 | if (!theme_setup(gui)) {
500 | gui_destroy_gui(gui);
501 | return 1;
502 | }
503 |
504 | TextureHandle colorpicker_image = gui_load_texture(gui, "color_picker.png");
505 |
506 | int memory_arena_capacity = 1024 * 1024 * 1;
507 | char* memory_arena = (char*)malloc(memory_arena_capacity);
508 | TheDebuginatorConfig config;
509 | debuginator_get_default_config(&config);
510 | config.memory_arena = memory_arena;
511 | config.memory_arena_capacity = memory_arena_capacity;
512 | config.draw_image = draw_image;
513 | config.draw_rect = draw_rect;
514 | config.draw_text = draw_text;
515 | config.word_wrap = word_wrap;
516 | config.text_size = text_size;
517 | config.log = log;
518 | config.play_sound = play_sound;
519 | config.app_user_data = (void*)gui;
520 | config.size.x = 500;
521 | config.size.y = (float)res_y;
522 | config.screen_resolution.x = (float)res_x;
523 | config.screen_resolution.y = (float)res_y;
524 | //config.open_direction = -1; // To show it on the right side of the screen
525 | config.create_default_debuginator_items = true;
526 | config.colorpicker_image.h.ull_value = colorpicker_image;
527 |
528 | TheDebuginator debuginator;
529 | debuginator_create(&config, &debuginator);
530 |
531 | char* loaded_data_buffer = (char*)malloc(10 * 1024 * 1024);
532 | bool load_result = load(&debuginator, loaded_data_buffer, 10 * 1024 * 1024);
533 | if (!load_result) {
534 | return 1;
535 | }
536 | free(loaded_data_buffer);
537 |
538 | GameData* gamedata = game_init(gui, &debuginator);
539 | DemoData* demodata = demo_init(gui, &debuginator);
540 |
541 | bool limit_framerate = false;
542 | debuginator_create_bool_item(&debuginator, "SDL Demo/Throttle framerate", "Disables sleeping between frames.", &limit_framerate);
543 |
544 | bool show_framerate = false;
545 | debuginator_create_bool_item(&debuginator, "SDL Demo/Show framerate", "Shows framerate and frame time in ms.", &show_framerate);
546 |
547 | const char* preset_paths[2] = { "SDL Demo/Throttle framerate", "SDL Demo/Show framerate" };
548 | const char* preset_value_titles[2] = { "True", "False" };
549 | debuginator_create_preset_item(&debuginator, "SDL Demo/Edit types/Preset", preset_paths, preset_value_titles, NULL, 2);
550 |
551 | float demo_y_offset = 0;
552 | debuginator_create_numberrange_float_item(&debuginator, "SDL Demo/Edit types/Number slider", "Example of the NumberRange edit type", &demo_y_offset, -100, 200);
553 |
554 | bool show_background = true;
555 | debuginator_create_bool_item(&debuginator, "SDL Demo/Show background image", "", &show_background);
556 | debuginator_create_array_item(&debuginator, NULL, "SDL Demo/Attributions", "Background image: sk5.jpg. See sk5.txt.", NULL, NULL, NULL, NULL, 0, 0);
557 |
558 | TextureHandle bg_texture = gui_load_texture(gui, "sk5.jpg");
559 |
560 | Uint64 START = SDL_GetPerformanceCounter();
561 | Uint64 NOW = START;
562 | Uint64 LAST = 0;
563 |
564 | SDL_Event event;
565 | bool quit = false;
566 | double time_since_button_pressed = 0;
567 | SDL_GameControllerButton current_button = SDL_CONTROLLER_BUTTON_INVALID;
568 | float gamepad_scroll_speed = 0;
569 | double time_now = 0;
570 | double bg_height = 0;
571 | while (!quit) {
572 | LAST = NOW;
573 | NOW = SDL_GetPerformanceCounter();
574 | Uint64 freq = SDL_GetPerformanceFrequency();
575 | double dt = (double)((NOW - LAST) * 1.0 / freq);
576 | time_now += dt;
577 | time_since_button_pressed += dt;
578 |
579 | while (SDL_PollEvent(&event) != 0)
580 | {
581 | if (handle_debuginator_keyboard_input_event(&event, &debuginator, demodata)) {
582 | continue;
583 | }
584 |
585 | if (handle_debuginator_gamepad_input_event(&event, &debuginator, current_button, time_since_button_pressed, gamepad_scroll_speed)) {
586 | continue;
587 | }
588 |
589 | switch (event.type) {
590 | case SDL_KEYDOWN:
591 | {
592 | if (event.key.keysym.sym == SDLK_ESCAPE) {
593 | quit = true;
594 | }
595 | break;
596 | }
597 | case SDL_QUIT:
598 | {
599 | quit = true;
600 | break;
601 | }
602 | case SDL_WINDOWEVENT : {
603 | switch (event.window.event) {
604 | case SDL_WINDOWEVENT_RESIZED: {
605 | debuginator_set_size(&debuginator, (int)debuginator.size.x, event.window.data2 );
606 | debuginator_set_screen_resolution(&debuginator, event.window.data1, event.window.data2 );
607 | res_x = event.window.data1;
608 | res_y = event.window.data2;
609 | } break;
610 | }
611 |
612 | break;
613 | }
614 | }
615 | }
616 |
617 | handle_debuginator_gamepad_input(&debuginator, current_button, time_since_button_pressed);
618 | handle_debuginator_gamepad_input_immediate(&debuginator, gui);
619 | if (gamepad_scroll_speed != 0) {
620 | debuginator_apply_scroll(&debuginator, (int)(gamepad_scroll_speed * dt));
621 | }
622 |
623 | debuginator_update(&debuginator, (float)dt);
624 |
625 | gui_frame_begin(gui);
626 |
627 | if (show_background) {
628 | bg_height = bg_height * (1 - 0.02) - 200 * 0.02;
629 | Vector2 bg_texture_pos = {0, (float)bg_height};
630 | Vector2 bg_texture_size = {(float)res_x, 0};
631 | gui_draw_texture(gui, bg_texture, bg_texture_pos, bg_texture_size);
632 | }
633 |
634 | Vector2 main_text_size = gui_text_size(gui, "The Debuginator", s_fonts[FONT_DemoHeader]);
635 | Vector2 main_text_pos(res_x / 2 - main_text_size.x / 2, res_y / 4 - main_text_size.y / 2 + demo_y_offset);
636 | float main_text_width = res_x - debuginator.openness * debuginator.size.x;
637 | float main_text_offset = debuginator.open_direction == 1 ? debuginator.openness * debuginator.size.x : 0;
638 | main_text_pos.x = main_text_offset + main_text_width / 2 - main_text_size.x / 2;
639 | unsigned char main_text_brightness = 80 + (unsigned char)(50*sin((double)(NOW-START) * 1 / freq));
640 | Color main_text_color(30 + main_text_brightness, 30 + main_text_brightness, main_text_brightness, 255);
641 | gui_draw_text(gui, "The Debuginator", main_text_pos, s_fonts[FONT_DemoHeader], main_text_color);
642 |
643 | game_update(gamedata, (float)dt);
644 |
645 | Vector2 demo_pos = main_text_pos;
646 | demo_pos.y += 100;
647 | demo_update(demodata, (float)dt, demo_pos);
648 |
649 | debuginator_draw(&debuginator, (float)dt);
650 |
651 | // Not a good way to enforce a framerate due to delay being inprecise but
652 | // its purpose is to save some battery, not to get exactly X fps.
653 | float fps = 30;
654 | float frame_time = 1 / fps;
655 | if (limit_framerate && frame_time > dt) {
656 | SDL_Delay((Uint32)(1000 * (frame_time - dt)));
657 | }
658 |
659 | if (show_framerate && dt > 0) {
660 | char fpsstr[64] = { 0 };
661 | sprintf_s(fpsstr, 64, "FPS: %.2lf / ms: %.15lf", 1/dt, dt * 1000);
662 | gui_draw_text(gui, fpsstr, Vector2(res_x * 0.5f, 20.f), s_fonts[FONT_ItemDescription], Color(255, 255, 0, 255));
663 | }
664 |
665 | gui_frame_end(gui);
666 | }
667 |
668 | for (size_t i = 0; i < 16; i++) { // TODO unhardcode
669 | if (s_fonts[i] != 0x0) { // TODO invalid handle
670 | gui_unregister_font_template(gui, s_fonts[i]);
671 | }
672 | }
673 |
674 | free(memory_arena);
675 | gui_destroy_gui(gui);
676 | return 0;
677 | }
678 |
--------------------------------------------------------------------------------
/tests/sdl/sdl.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}
36 | sdl
37 | 10.0
38 |
39 |
40 |
41 | Application
42 | true
43 | v142
44 | MultiByte
45 |
46 |
47 | Application
48 | false
49 | v142
50 | true
51 | MultiByte
52 |
53 |
54 | Application
55 | true
56 | v142
57 | MultiByte
58 |
59 |
60 | Application
61 | false
62 | v142
63 | true
64 | MultiByte
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 | $(IncludePath)
86 |
87 |
88 | $(IncludePath)
89 | $(SolutionDir)\Build\$(Platform)_$(Configuration)\
90 | $(SolutionDir)\Build\_$(ProjectName)\$(Platform)_$(Configuration)\
91 | TheDebuginator_SDLDemo_Debug
92 |
93 |
94 | $(SolutionDir)\Build\$(Platform)_$(Configuration)\
95 | $(SolutionDir)\Build\_$(ProjectName)\$(Platform)_$(Configuration)\
96 | TheDebuginator_SDLDemo
97 |
98 |
99 |
100 | Level4
101 | Disabled
102 | true
103 | $(SolutionDir)..\..\external\SDL2-2.0.9\include;%(AdditionalIncludeDirectories)
104 |
105 |
106 | SDL2.lib;SDL2main.lib;%(AdditionalDependencies)
107 | D:\projects\external\sdl\SDL2-2.0.8\lib\x86;%(AdditionalLibraryDirectories)
108 | Console
109 |
110 |
111 |
112 |
113 | Level4
114 | Disabled
115 | true
116 | $(SolutionDir)..\..\external\SDL2-2.0.9\include;$(SolutionDir)..\..\external\SDL2_image-2.0.2\include;$(SolutionDir)..\..\external\SDL2_ttf-2.0.14\include;$(SolutionDir)3rdparty\Simple-SDL2-Audio\src;%(AdditionalIncludeDirectories)
117 | true
118 |
119 |
120 | SDL2.lib;SDL2main.lib;SDL2_image.lib;SDL2_ttf.lib;%(AdditionalDependencies)
121 | $(SolutionDir)..\..\external\SDL2-2.0.9\lib\x64;$(SolutionDir)..\..\external\SDL2_ttf-2.0.14\lib\x64;$(SolutionDir)..\..\external\SDL2_image-2.0.2\lib\x64
122 | Console
123 |
124 |
125 |
126 |
127 |
128 |
129 | copy $(SolutionDir)..\..\external\SDL2-2.0.9\lib\x64\SDL2.dll $(OutputPath)
130 |
131 | copy $(SolutionDir)..\..\external\SDL2_ttf-2.0.14\lib\x64\*.dll $(OutputPath)
132 |
133 | copy $(SolutionDir)..\..\external\SDL2_image-2.0.2\lib\x64\*.dll $(OutputPath)
134 |
135 | copy $(SolutionDir)3rdparty\liberation-fonts-ttf-2.00.1\*.ttf $(OutputPath)
136 |
137 | copy $(SolutionDir)..\color_picker.png $(OutputPath)
138 | copy $(SolutionDir)sk5.jpg $(OutputPath)
139 | copy $(SolutionDir)sk5.txt $(OutputPath)
140 |
141 | copy $(SolutionDir)3rdparty\SDL_GameControllerDB-master\gamecontrollerdb.txt $(OutputPath)
142 |
143 | copy $(SolutionDir)3rdparty\kenney_interfacesounds\*.wav $(OutputPath)
144 |
145 |
146 |
147 |
148 |
149 |
150 | Level4
151 | MaxSpeed
152 | true
153 | true
154 | true
155 | $(SolutionDir)..\..\external\SDL2-2.0.9\include;%(AdditionalIncludeDirectories)
156 |
157 |
158 | true
159 | true
160 |
161 |
162 |
163 |
164 | Level4
165 | MaxSpeed
166 | true
167 | true
168 | true
169 | $(SolutionDir)..\..\external\SDL2-2.0.9\include;$(SolutionDir)..\..\external\SDL2_image-2.0.2\include;$(SolutionDir)..\..\external\SDL2_ttf-2.0.14\include;$(SolutionDir)3rdparty\Simple-SDL2-Audio\src;%(AdditionalIncludeDirectories)
170 |
171 |
172 | true
173 | true
174 | Console
175 | SDL2.lib;SDL2main.lib;SDL2_image.lib;SDL2_ttf.lib;%(AdditionalDependencies)
176 | $(SolutionDir)..\..\external\SDL2-2.0.9\lib\x64;$(SolutionDir)..\..\external\SDL2_ttf-2.0.14\lib\x64;$(SolutionDir)..\..\external\SDL2_image-2.0.2\lib\x64
177 |
178 |
179 | copy $(SolutionDir)..\..\external\SDL2-2.0.9\lib\x64\SDL2.dll $(OutputPath)
180 |
181 | copy $(SolutionDir)..\..\external\SDL2_ttf-2.0.14\lib\x64\*.dll $(OutputPath)
182 |
183 | copy $(SolutionDir)..\..\external\SDL2_image-2.0.2\lib\x64\*.dll $(OutputPath)
184 |
185 | copy $(SolutionDir)3rdparty\liberation-fonts-ttf-2.00.1\*.ttf $(OutputPath)
186 |
187 | copy $(SolutionDir)..\color_picker.png $(OutputPath)
188 |
189 | copy $(SolutionDir)3rdparty\SDL_GameControllerDB-master\gamecontrollerdb.txt $(OutputPath)
190 |
191 |
192 |
193 |
194 |
195 |
--------------------------------------------------------------------------------
/tests/sdl/sdl.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/sk5.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Srekel/the-debuginator/15614a72c26ef15db55b6c715dea6bfe2deb5b3e/tests/sk5.jpg
--------------------------------------------------------------------------------
/tests/sk5.txt:
--------------------------------------------------------------------------------
1 | For sk5.jpg
2 | Licensed under CC BY 4.0 https://creativecommons.org/licenses/by/4.0/
3 | Source: https://opengameart.org/content/kujasa-the-beginning
4 |
5 | Copyright/Attribution Notice:
6 | Sergei Churbanov, aka CatBlack, graphic artist
7 | William Thompson, contributor
8 |
--------------------------------------------------------------------------------
/tests/the-debuginator.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unittest", "unittest\unittest.vcxproj", "{97FE62A5-44C3-4741-882F-FC515FDC8A86}"
7 | EndProject
8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sdl", "sdl\sdl.vcxproj", "{56259B2E-7D95-4AB0-83E4-369B9361F8A2}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|x64 = Debug|x64
13 | Debug|x86 = Debug|x86
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Debug|x64.ActiveCfg = Debug|x64
19 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Debug|x64.Build.0 = Debug|x64
20 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Debug|x86.ActiveCfg = Debug|Win32
21 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Debug|x86.Build.0 = Debug|Win32
22 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Release|x64.ActiveCfg = Release|x64
23 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Release|x64.Build.0 = Release|x64
24 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Release|x86.ActiveCfg = Release|Win32
25 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}.Release|x86.Build.0 = Release|Win32
26 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Debug|x64.ActiveCfg = Debug|x64
27 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Debug|x64.Build.0 = Debug|x64
28 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Debug|x86.ActiveCfg = Debug|Win32
29 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Debug|x86.Build.0 = Debug|Win32
30 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Release|x64.ActiveCfg = Release|x64
31 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Release|x64.Build.0 = Release|x64
32 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Release|x86.ActiveCfg = Release|Win32
33 | {56259B2E-7D95-4AB0-83E4-369B9361F8A2}.Release|x86.Build.0 = Release|Win32
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | EndGlobal
39 |
--------------------------------------------------------------------------------
/tests/the-debuginator_solution_suppressions.cfg:
--------------------------------------------------------------------------------
1 | [cppcheck]
2 | cstyleCast
3 | memsetClassFloat
4 | missingInclude
5 | missingIncludeSystem
6 | variableScope:*main.cpp
7 | constStatement
8 | [cppcheck_files]
9 | [cppcheck_includes]
10 |
--------------------------------------------------------------------------------
/tests/unittest/unittest.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 |
6 | #ifndef __cplusplus
7 | #include
8 | #endif
9 |
10 | #ifdef _MSC_VER
11 | #pragma warning( disable: 4464 4548 4710 4820 )
12 | #endif
13 |
14 | #ifdef __clang__
15 |
16 | #endif
17 | typedef struct UnitTestData
18 | {
19 | char errors[256][256];
20 | unsigned error_index;
21 | unsigned num_tests;
22 |
23 | bool simplebool_target;
24 | bool generatedbool_target;
25 |
26 | char stringtest[256];
27 | } UnitTestData;
28 |
29 | static UnitTestData g_testdata;
30 |
31 | static void unittest_debuginator_assert(bool test) {
32 | ++g_testdata.num_tests;
33 | if (g_testdata.error_index == 256) {
34 | assert(false);
35 | }
36 | if (!test) {
37 | memcpy(g_testdata.errors[g_testdata.error_index++], "LOL", 4);
38 | }
39 | //DebugBreak();
40 | }
41 |
42 | #define DEBUGINATOR_assert unittest_debuginator_assert
43 | #define DEBUGINATOR_static_assert unittest_debuginator_assert
44 | #define ASSERT unittest_debuginator_assert
45 |
46 | #define DEBUGINATOR_debug_print printf
47 | #define DEBUGINATOR_IMPLEMENTATION
48 |
49 | #include "../../the_debuginator.h"
50 |
51 | // Debuginator Callbacks
52 | #pragma warning(suppress: 4100) // Unreferenced param
53 | void draw_text(const char* text, DebuginatorVector2* position, DebuginatorColor* color, DebuginatorFont* font, void* userdata) {
54 | }
55 |
56 | #pragma warning(suppress: 4100) // Unreferenced param
57 | void draw_rect(DebuginatorVector2* position, DebuginatorVector2* size, DebuginatorColor* color, void* userdata) {
58 | }
59 |
60 | #pragma warning(suppress: 4100) // Unreferenced param
61 | void word_wrap(const char* text, DebuginatorFont font, float max_width, int* row_count, int* row_lengths, int row_lengths_buffer_size, void* app_userdata) {
62 | *row_count = 0;
63 | }
64 |
65 | #pragma warning(suppress: 4100) // Unreferenced param
66 | DebuginatorVector2 text_size(const char* text, DebuginatorFont* font, void* userdata) {
67 | DebuginatorVector2 size = {0, 0};
68 | return size;
69 | }
70 |
71 | // Item callback
72 | static void unittest_on_item_changed_stringtest(DebuginatorItem* item, void* value, const char* value_title, void* app_userdata) {
73 | (void)value_title;
74 | (void)app_userdata;
75 | const char** string_ptr = (const char**)value;
76 | UnitTestData* callback_data = (UnitTestData*)item->user_data; // same as &g_testdata
77 |
78 | #ifdef __cplusplus
79 | strncpy_s(callback_data->stringtest, *string_ptr, strlen(*string_ptr));
80 | #else
81 | strncpy_s(callback_data->stringtest, sizeof(callback_data->stringtest), *string_ptr, strlen(*string_ptr));
82 | #endif
83 | }
84 |
85 | static void unittest_debug_menu_setup(TheDebuginator* debuginator) {
86 | debuginator_create_bool_item(debuginator, "SimpleBool 1", "Change a bool.", &g_testdata.simplebool_target);
87 | debuginator_create_bool_item(debuginator, "Folder/SimpleBool 2", "Change a bool.", &g_testdata.simplebool_target);
88 | debuginator_create_bool_item(debuginator, "Folder/SimpleBool 3", "Change a bool.", &g_testdata.simplebool_target);
89 | debuginator_create_bool_item(debuginator, "Folder/SimpleBool 4 with a really really long title", "Change a bool.", &g_testdata.simplebool_target);
90 |
91 | debuginator_create_folder_item(debuginator, NULL, "Folder 2");
92 |
93 | static const char* string_values[3] = { "gamestring 1", "gamestring 2", "gamestring 3"};
94 | static const char* string_titles[3] = { "First value", "Second one", "This is the third." };
95 | debuginator_create_array_item(debuginator, NULL, "Folder 2/String item",
96 | "Do it", unittest_on_item_changed_stringtest, &g_testdata,
97 | string_titles, (void*)string_values, 3, sizeof(string_values[0]));
98 | }
99 |
100 | static void unittest_debug_menu_run(void) {
101 |
102 | memset(&g_testdata, 0, sizeof(g_testdata));
103 | UnitTestData* testdata = &g_testdata;
104 |
105 |
106 | int memory_arena_capacity = 1024 * 1024 * 1;
107 | char* memory_arena = (char*)malloc(memory_arena_capacity);
108 | TheDebuginatorConfig config;
109 | debuginator_get_default_config(&config);
110 | config.memory_arena = memory_arena;
111 | config.memory_arena_capacity = memory_arena_capacity;
112 | config.draw_rect = draw_rect;
113 | config.draw_text = draw_text;
114 | config.word_wrap = word_wrap;
115 | config.text_size = text_size;
116 | config.app_user_data = &g_testdata;
117 | config.size.x = 500;
118 | config.size.y = 1000;
119 | config.screen_resolution.x = 500;
120 | config.screen_resolution.y = 1000;
121 | config.focus_height = 0.3f;
122 | config.create_default_debuginator_items = false;
123 |
124 | TheDebuginator debuginator;
125 | TheDebuginator* thed = &debuginator; // Lazy shorthand
126 | debuginator_create(&config, thed);
127 |
128 | unittest_debug_menu_setup(thed);
129 |
130 | printf("\n");
131 | printf("Setup errors found: %u/%u\n",
132 | testdata->error_index, testdata->num_tests);
133 |
134 | if (testdata->error_index > 0) {
135 | printf("Errors found during setup, exiting.\n");
136 | return;
137 | }
138 |
139 | testdata->num_tests = 0;
140 |
141 | DebuginatorItem* sb1_item = debuginator_get_item(thed, NULL, "SimpleBool 1", false);
142 | DebuginatorItem* sb2_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 2", false);
143 | DebuginatorItem* sb3_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 3", false);
144 | DebuginatorItem* sb4_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 4 with a really really long title", false);
145 | DebuginatorItem* str_item = debuginator_get_item(thed, NULL, "Folder 2/String item", false);
146 |
147 | {
148 | // Are our expectations after setup correct?
149 | ASSERT(sb1_item != NULL);
150 | ASSERT(sb2_item != NULL);
151 | ASSERT(sb3_item != NULL);
152 | ASSERT(sb4_item != NULL);
153 | ASSERT(str_item != NULL);
154 |
155 | ASSERT(debuginator.root->folder.num_visible_children = 5);
156 |
157 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "SimpleBool 1", false);
158 | ASSERT(expected_hot_item == debuginator.hot_item);
159 | ASSERT(expected_hot_item->leaf.is_expanded == false);
160 |
161 | ASSERT(testdata->simplebool_target == false);
162 | ASSERT(testdata->generatedbool_target == false);
163 | }
164 | {
165 | // Can we add and remove stuff?
166 | char item_name[64] = { 0 };
167 | for (int i = 0; i < 10; i++) {
168 | for (int j = 0; j < 10; j++) {
169 | sprintf_s(item_name, 64, "Game/Test%02d/GameBool%02d", i, j);
170 | debuginator_create_bool_item(thed, item_name, "Generated bool item.", &g_testdata.generatedbool_target);
171 | }
172 | }
173 |
174 | ASSERT(debuginator.root->folder.num_visible_children == 6);
175 |
176 | DebuginatorItem* game_item = debuginator_get_item(thed, NULL, "Game", false);
177 | ASSERT(game_item->folder.num_visible_children == 10);
178 |
179 | DebuginatorItem* remove_item = debuginator_get_item(thed, NULL, "Game/Test01", false);
180 | debuginator_remove_item(thed, remove_item);
181 | ASSERT(game_item->folder.num_visible_children == 9);
182 |
183 | for (int i = 0; i < 10; i++) {
184 | for (int j = 0; j < 10; j++) {
185 | sprintf_s(item_name, 64, "Game/Test%02d/GameBool%02d", i, j);
186 | debuginator_create_bool_item(thed, item_name, "Generated bool item.", &g_testdata.generatedbool_target);
187 | }
188 | }
189 |
190 | ASSERT(game_item->folder.num_visible_children == 10);
191 |
192 | remove_item = debuginator_get_item(thed, NULL, "Game/Test01", false);
193 | debuginator_remove_item(thed, remove_item);
194 |
195 | ASSERT(game_item->folder.num_visible_children == 9);
196 | }
197 |
198 | /*
199 | {
200 | debuginator_move_to_next_leaf(thed, false);
201 | // Going to child activates SimpleBool 1
202 | DebuginatorInput input = {0};
203 | input.move_to_child = true;
204 | debug_menu_handle_input(thed, &input);
205 | ASSERT(debuginator.hot_item->leaf.is_expanded == true);
206 | }
207 | {
208 | // Going to child changes SimpleBool 1 bool
209 | DebuginatorInput input = {0};
210 | input.move_to_child = true;
211 | debug_menu_handle_input(thed, &input);
212 | ASSERT(testdata->simplebool_target == false);
213 | }
214 | {
215 | // Going to child and sibling at the same time changes SimpleBool 1's to second option and sets bool to true
216 | DebuginatorInput input = {0};
217 | input.move_to_child = true;
218 | input.move_sibling_next = true;
219 | debug_menu_handle_input(thed, &input);
220 | ASSERT(testdata->simplebool_target == true);
221 | }
222 | {
223 | // Going to child SimpleBool 1's first option changes bool to false
224 | DebuginatorInput input = {0};
225 | input.move_to_child = true;
226 | input.move_sibling_next = true;
227 | debug_menu_handle_input(thed, &input);
228 | ASSERT(testdata->simplebool_target == false);
229 | }
230 | {
231 | // Going to parent inactivates item
232 | DebuginatorInput input = {0};
233 | input.move_to_parent = true;
234 | debug_menu_handle_input(thed, &input);
235 | ASSERT(debuginator.hot_item->leaf.is_expanded == false);
236 | }
237 | {
238 | // Going to parent does nothing
239 | DebuginatorInput input = {0};
240 | input.move_to_parent = true;
241 | debug_menu_handle_input(thed, &input);
242 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "SimpleBool 1", false);
243 | ASSERT(expected_hot_item == debuginator.hot_item);
244 | }
245 | {
246 | // Going down goes to Folder
247 | DebuginatorInput input = {0};
248 | input.move_sibling_next = true;
249 | debug_menu_handle_input(thed, &input);
250 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder", false);
251 | ASSERT(expected_hot_item == debuginator.hot_item);
252 | }
253 | {
254 | // Going down goes to Folder 2
255 | DebuginatorInput input = {0};
256 | input.move_sibling_next = true;
257 | debug_menu_handle_input(thed, &input);
258 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder 2", false);
259 | ASSERT(expected_hot_item == debuginator.hot_item);
260 | }
261 | {
262 | // Going down wraps to SimpleBool 1
263 | DebuginatorInput input = {0};
264 | input.move_sibling_next = true;
265 | debug_menu_handle_input(thed, &input);
266 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "SimpleBool 1", false);
267 | ASSERT(expected_hot_item == debuginator.hot_item);
268 | }
269 | {
270 | // Go to Folder
271 | DebuginatorInput input = {0};
272 | input.move_sibling_next = true;
273 | debug_menu_handle_input(thed, &input);
274 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder", false);
275 | ASSERT(expected_hot_item == debuginator.hot_item);
276 | }
277 | {
278 | // Going to child goes to SimpleBool 2
279 | DebuginatorInput input = {0};
280 | input.move_to_child = true;
281 | debug_menu_handle_input(thed, &input);
282 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 2", false);
283 | ASSERT(expected_hot_item == debuginator.hot_item);
284 | }
285 | {
286 | // Going to child activates SimpleBool 2
287 | DebuginatorInput input = {0};
288 | input.move_to_child = true;
289 | debug_menu_handle_input(thed, &input);
290 | ASSERT(debuginator.hot_item->leaf.is_expanded == true);
291 | }
292 | {
293 | // Going to child changes SimpleBool 2 bool
294 | DebuginatorInput input = {0};
295 | input.move_to_child = true;
296 | debug_menu_handle_input(thed, &input);
297 | ASSERT(testdata->simplebool_target == false);
298 | }
299 | {
300 | // Going to parent inactivates item
301 | DebuginatorInput input = {0};
302 | input.move_to_parent = true;
303 | debug_menu_handle_input(thed, &input);
304 | ASSERT(debuginator.hot_item->leaf.is_expanded == false);
305 | }
306 | {
307 | // Going to sibling works as expected
308 | DebuginatorInput input = {0};
309 | input.move_sibling_next = true;
310 | debug_menu_handle_input(thed, &input);
311 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 3", false);
312 | ASSERT(expected_hot_item == debuginator.hot_item);
313 |
314 | debug_menu_handle_input(thed, &input);
315 | expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 4 with a really long long title", false);
316 | ASSERT(expected_hot_item == debuginator.hot_item);
317 |
318 | debug_menu_handle_input(thed, &input);
319 | expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 2", false);
320 | ASSERT(expected_hot_item == debuginator.hot_item);
321 |
322 | debug_menu_handle_input(thed, &input);
323 | expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 3", false);
324 | ASSERT(expected_hot_item == debuginator.hot_item);
325 | }
326 | {
327 | // Go to Folder 2/String item
328 | DebuginatorInput input = {0};
329 | input.move_to_parent = true;
330 | debug_menu_handle_input(thed, &input);
331 | debug_menu_handle_input(thed, &input);
332 | input.move_to_parent = false;
333 | input.move_sibling_next = true;
334 | input.move_to_child = true;
335 | debug_menu_handle_input(thed, &input);
336 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder 2/String item", false);
337 | ASSERT(expected_hot_item == debuginator.hot_item);
338 | }
339 | {
340 | // Going to child activates string item
341 | DebuginatorInput input = {0};
342 | input.move_to_child = true;
343 | debug_menu_handle_input(thed, &input);
344 | ASSERT(debuginator.hot_item->leaf.is_expanded == true);
345 | }
346 | {
347 | // Going to child changes string
348 | DebuginatorInput input = {0};
349 | input.move_to_child = true;
350 | debug_menu_handle_input(thed, &input);
351 | ASSERT(strcmp(testdata->stringtest, "gamestring 1") == 0);
352 | }
353 | {
354 | // Going down goes to next string
355 | DebuginatorInput input = {0};
356 | input.move_sibling_next = true;
357 | debug_menu_handle_input(thed, &input);
358 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder 2/String item", false);
359 | ASSERT(expected_hot_item == debuginator.hot_item);
360 | }
361 | {
362 | // Going to child changes string
363 | DebuginatorInput input = {0};
364 | input.move_to_child = true;
365 | debug_menu_handle_input(thed, &input);
366 | ASSERT(strcmp(testdata->stringtest, "gamestring 2") == 0);
367 | }
368 | {
369 | // Overwrite the item with another item
370 | debuginator_create_bool_item(thed, "Folder 2/String item", "Change a bool.", &testdata->simplebool_target);
371 | }
372 | {
373 | // Activate it, we should still be on the second value, so bool should turn to true
374 | ASSERT(testdata->simplebool_target == false);
375 | DebuginatorInput input = {0};
376 | input.move_to_child = true;
377 | debug_menu_handle_input(thed, &input);
378 | ASSERT(testdata->simplebool_target == true);
379 | }
380 | {
381 | // Remove item
382 | debuginator_remove_item_by_path(thed, "Folder 2/String item");
383 | DebuginatorItem* expected_null_item = debuginator_get_item(thed, NULL, "Folder 2/String item", false);
384 | ASSERT(expected_null_item == NULL);
385 |
386 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder 2", false);
387 | ASSERT(expected_hot_item == debuginator.hot_item);
388 | }
389 | {
390 | // Set hot item
391 | debuginator_set_hot_item(thed, "Folder/SimpleBool 2");
392 |
393 | DebuginatorItem* expected_hot_item = debuginator_get_item(thed, NULL, "Folder/SimpleBool 2", false);
394 | ASSERT(expected_hot_item == debuginator.hot_item);
395 | }
396 |
397 | */
398 |
399 | printf("Run errors found: %u/%u\n",
400 | testdata->error_index, testdata->num_tests);
401 |
402 | printf("\n");
403 | if (testdata->error_index == 0) {
404 | printf("No errors found, YAY!\n");
405 | }
406 | else {
407 | printf("U are teh sux.\n");
408 | }
409 | }
410 |
411 | int main(int argc, char **argv)
412 | {
413 | (void)(argc, argv);
414 | unittest_debug_menu_run();
415 |
416 | while (true)
417 | {
418 |
419 | }
420 | return 0;
421 | }
422 |
--------------------------------------------------------------------------------
/tests/unittest/unittest.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {97FE62A5-44C3-4741-882F-FC515FDC8A86}
23 | Win32Proj
24 | thedebuginator
25 | 10.0.14393.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | Unicode
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | Unicode
40 |
41 |
42 | Application
43 | true
44 | v141
45 | Unicode
46 |
47 |
48 | Application
49 | false
50 | v141
51 | true
52 | Unicode
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | true
74 |
75 |
76 | true
77 | $(SolutionDir)\Build\$(Platform)_$(Configuration)\
78 | $(SolutionDir)\Build\_$(ProjectName)\$(Platform)_$(Configuration)\
79 |
80 |
81 | false
82 |
83 |
84 | false
85 |
86 |
87 |
88 |
89 |
90 | Level3
91 | Disabled
92 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
93 | true
94 |
95 |
96 | Console
97 | true
98 |
99 |
100 |
101 |
102 |
103 |
104 | EnableAllWarnings
105 | Disabled
106 | _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
107 | true
108 | true
109 |
110 |
111 | Console
112 | true
113 |
114 |
115 |
116 |
117 | Level3
118 |
119 |
120 | MaxSpeed
121 | true
122 | true
123 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
124 | true
125 |
126 |
127 | Console
128 | true
129 | true
130 | true
131 |
132 |
133 |
134 |
135 | Level3
136 |
137 |
138 | MaxSpeed
139 | true
140 | true
141 | NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
142 | true
143 |
144 |
145 | Console
146 | true
147 | true
148 | true
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/tests/unittest/unittest.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/zig-minimal/build.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 |
3 | cls
4 | cd src
5 | zig build run
6 | cd ..
--------------------------------------------------------------------------------
/tests/zig-minimal/src/build.zig:
--------------------------------------------------------------------------------
1 |
2 |
3 | const std = @import("std");
4 | const builtin = @import("builtin");
5 |
6 | pub fn build(b: *std.build.Builder) anyerror!void {
7 | b.release_mode = builtin.Mode.Debug;
8 | const mode = b.standardReleaseOptions();
9 |
10 | const mainFile = "main.zig";
11 | var exe = b.addExecutable("debuginator-zig-demo", "../src/" ++ mainFile);
12 | exe.addIncludeDir("../src/");
13 | exe.addIncludeDir("../../..");
14 | exe.setBuildMode(mode);
15 |
16 | const cFlags = [_][]const u8{"-std=c99"};
17 | exe.addCSourceFile("the_debuginator_wrapper.c", &cFlags);
18 |
19 | exe.linkLibC();
20 | exe.linkSystemLibrary("user32");
21 | exe.linkSystemLibrary("gdi32");
22 |
23 | const run_cmd = exe.run();
24 | const run_step = b.step("run", "Run 'The Debuginator Zig Demo'");
25 | run_step.dependOn(&run_cmd.step);
26 |
27 | b.default_step.dependOn(&exe.step);
28 | b.installArtifact(exe);
29 | }
30 |
--------------------------------------------------------------------------------
/tests/zig-minimal/src/c.zig:
--------------------------------------------------------------------------------
1 | pub usingnamespace @cImport({
2 | @cInclude("the_debuginator_wrapper.h");
3 | });
4 |
5 | // pub usingnamespace @cImport("c.c");
6 |
7 | // const local = struct {
8 | // export fn debuginator_assert(condition: bool) void {
9 | // if (!condition) unreachable;
10 | // }
11 | // export fn de buginator_sprintf_s(varargs: anytype) void {}
12 | // export fn debuginator_strcpy_s(varargs: anytype) void {}
13 | // };
14 |
--------------------------------------------------------------------------------
/tests/zig-minimal/src/main.zig:
--------------------------------------------------------------------------------
1 | const std = @import("std");
2 | const debuginator_c = @import("c.zig");
3 |
4 | pub export fn draw_rect(position: [*c]debuginator_c.DebuginatorVector2, size: [*c]debuginator_c.DebuginatorVector2, color: [*c]debuginator_c.DebuginatorColor, userdata: ?*c_void) void {}
5 | pub export fn draw_text(text: [*c]const u8, position: [*c]debuginator_c.DebuginatorVector2, color: [*c]debuginator_c.DebuginatorColor, font: [*c]debuginator_c.DebuginatorFont, userdata: ?*c_void) void {}
6 | pub export fn text_size(text: [*c]const u8, font: [*c]debuginator_c.DebuginatorFont, userdata: ?*c_void) debuginator_c.DebuginatorVector2 {
7 | var size = debuginator_c.DebuginatorVector2{
8 | .x = 30,
9 | .y = 10,
10 | };
11 | return size;
12 | }
13 |
14 | pub export fn word_wrap(text: [*c]const u8, font: [*c]debuginator_c.DebuginatorFont, max_width: f32, row_count: [*c]c_int, row_lengths: [*c]c_int, row_lengths_buffer_size: c_int, userdata: ?*c_void) void {
15 | // std.debug.print("WW {}\n", .{max_width});
16 | }
17 |
18 | pub export fn log(text: [*c]const u8, userdata: ?*c_void) void {
19 | std.debug.print("LOG {}\n", .{text});
20 | }
21 |
22 |
23 | pub fn main() void {
24 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
25 | defer arena.deinit();
26 |
27 | const buffer_size = 1024 * 1024;
28 | var buffer = arena.allocator.alloc(u8, buffer_size) catch unreachable;
29 |
30 | var config = std.mem.zeroes(debuginator_c.TheDebuginatorConfig);
31 | debuginator_c.debuginator_get_default_config(&config);
32 | config.memory_arena = @ptrCast([*c]u8, buffer);
33 | config.memory_arena_capacity = buffer_size;
34 | config.draw_rect = draw_rect;
35 | config.draw_text = draw_text;
36 | config.text_size = text_size;
37 | config.word_wrap = word_wrap;
38 | config.log = log;
39 | config.size.x = 300;
40 | config.size.y = 1000;
41 | config.screen_resolution.x = 1200;
42 | config.screen_resolution.y = config.size.y;
43 | config.app_user_data = &config;
44 |
45 |
46 | std.debug.print("BEGIN {}\n", .{config.create_default_debuginator_items});
47 | var debuginator: ?*debuginator_c.TheDebuginator = debuginator_c.alloc_debuginator();
48 | std.debug.assert(debuginator != null);
49 |
50 | std.debug.print("CREATE {}\n", .{config.create_default_debuginator_items});
51 | debuginator_c.debuginator_create(&config, debuginator);
52 |
53 | std.debug.print("UPDATE {}\n", .{config.create_default_debuginator_items});
54 | debuginator_c.debuginator_update(debuginator, 0.1);
55 | debuginator_c.debuginator_draw(debuginator, 0.1);
56 |
57 | std.debug.print("END {}\n", .{config.create_default_debuginator_items});
58 | }
59 |
--------------------------------------------------------------------------------
/tests/zig-minimal/src/the_debuginator_wrapper.c:
--------------------------------------------------------------------------------
1 |
2 | #define DEBUGINATOR_IMPLEMENTATION
3 | #include
4 |
5 |
6 | struct TheDebuginator* alloc_debuginator() {
7 | static struct TheDebuginator debuginator;
8 | memset(&debuginator, 0, sizeof(debuginator));
9 | return &debuginator;
10 | }
11 |
--------------------------------------------------------------------------------
/tests/zig-minimal/src/the_debuginator_wrapper.h:
--------------------------------------------------------------------------------
1 |
2 | #include "the_debuginator.h"
3 |
4 | struct TheDebuginator* alloc_debuginator();
5 |
--------------------------------------------------------------------------------
/the_debuginator_queue.h:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | the_debuginator_queue.h - v0.01 - public domain - Anders Elfgren @srekel, 2018
4 |
5 | # THE DEBUGINATOR QUEUE
6 |
7 | A utility library to enable simple multi-threading support for The Debuginator.
8 |
9 | See github for latest version: https://github.com/Srekel/the-debuginator
10 |
11 | ## Usage
12 |
13 | In *ONE* source file, put:
14 |
15 | ```C
16 | #define DEBUGINATOR_QUEUE_IMPLEMENTATION
17 |
18 | // Define any of these if you wish to override them.
19 | // (There are more. Find them in the beginning of the code.)
20 | #define DEBUGINATOR_assert
21 | #define DEBUGINATOR_memcpy
22 | #define DEBUGINATOR_fabs
23 |
24 | #include "the_debuginator.h"
25 | #include "the_debuginator_queue.h"
26 | ```
27 |
28 | Depending on if its in a binary that has actual access to the debuginator,
29 | also #define DEBUGINATOR_QUEUE_CAN_PROCEES
30 |
31 | Other source files should just include the_debuginator_queue.h
32 |
33 | ## Notes
34 |
35 | See the documentation on the github page.
36 |
37 | ## License
38 |
39 | Basically Public Domain / MIT.
40 | See end of file for license information.
41 |
42 | */
43 |
44 | #ifndef INCLUDE_THE_DEBUGINATOR_QUEUE_H
45 | #define INCLUDE_THE_DEBUGINATOR_QUEUE_H
46 |
47 | #include "the_debuginator.h"
48 |
49 | #ifdef __cplusplus
50 | extern "C" {
51 | #endif
52 |
53 | #ifndef DEBUGINATOR_ENABLE_WARNINGS
54 | #ifdef _MSC_VER
55 | #pragma warning( push, 0 )
56 | // #pragma warning( disable: 4820 4201)
57 | #endif
58 |
59 | #ifdef __clang__
60 | #pragma clang diagnostic push
61 | #pragma clang diagnostic ignored "-Wold-style-cast"
62 | #pragma clang diagnostic ignored "-Wsign-conversion"
63 | #pragma clang diagnostic ignored "-Wunused-value"
64 | #pragma clang diagnostic ignored "-Wcomma"
65 | #pragma clang diagnostic ignored "-Wcast-align"
66 | #pragma clang diagnostic ignored "-Wswitch-enum"
67 | #endif
68 | #endif
69 |
70 | #define DEBUGINATOR_QUEUE_MAX_PATH_LENGTH 128
71 | #define DEBUGINATOR_QUEUE_MAX_DESCRIPTION_LENGTH 512
72 |
73 | typedef enum DebuginatorQueueItemTypes {
74 | DEBUGINATOR_QUEUE_CreateItem,
75 | DEBUGINATOR_QUEUE_NumItemTypes
76 | } DebuginatorQueueItemTypes;
77 |
78 | typedef struct {
79 | char path[DEBUGINATOR_QUEUE_MAX_PATH_LENGTH];
80 | char description[DEBUGINATOR_QUEUE_MAX_DESCRIPTION_LENGTH];
81 | void* userdata;
82 | DebuginatorOnItemChangedCallback callback;
83 | } DebuginatorQueue_CreateItemData;
84 |
85 | typedef struct DebuginatorQueueItem {
86 | DebuginatorQueueItemTypes type;
87 | union {
88 | DebuginatorQueue_CreateItemData create_item;
89 | } data;
90 | } DebuginatorQueueItem;
91 |
92 | typedef struct TheDebuginatorQueue TheDebuginatorQueue;
93 |
94 | typedef void* ( *DebuginatorQueueAllocateFunc )( void* userdata, int bytes );
95 | typedef void ( *DebuginatorQueueDellocateFunc )( void* userdata, void* ptr );
96 | typedef void ( *DebuginatorQueueItemCleanupFunc )( TheDebuginatorQueue* queue,
97 | DebuginatorQueueItem* item );
98 |
99 | typedef struct TheDebuginatorQueue {
100 | void* userdata;
101 | DebuginatorQueueItem* items;
102 | int num_items;
103 | int capacity;
104 | DebuginatorQueueAllocateFunc allocate;
105 | DebuginatorQueueDellocateFunc deallocate;
106 | DebuginatorQueueItemCleanupFunc cleanup_funcs[DEBUGINATOR_QUEUE_NumItemTypes];
107 | } TheDebuginatorQueue;
108 |
109 | TheDebuginatorQueue* debuginator_queue_create( int initial_size,
110 | DebuginatorQueueAllocateFunc allocate_func,
111 | DebuginatorQueueDellocateFunc deallocate_func,
112 | void* userdata );
113 |
114 | unsigned char* debuginator_queue_data( TheDebuginatorQueue* queue, int* out_size );
115 | void debuginator_queue_clear( TheDebuginatorQueue* queue );
116 | void debuginator_queue_process( const unsigned char* data, int size, TheDebuginator* debuginator );
117 | void debuginator_queue_create_bool_item( TheDebuginatorQueue* queue,
118 | const char* path,
119 | const char* description,
120 | void* userdata );
121 | void debuginator_queue_create_bool_item_with_callback( TheDebuginatorQueue* queue,
122 | const char* path,
123 | const char* description,
124 | void* userdata,
125 | DebuginatorOnItemChangedCallback callback );
126 |
127 | #ifdef __cplusplus
128 | }
129 | #endif
130 |
131 | #ifdef DEBUGINATOR_QUEUE_IMPLEMENTATION
132 |
133 | #ifndef DEBUGINATOR_QUEUE_assert
134 | #include
135 | #define DEBUGINATOR_QUEUE_assert assert;
136 | #endif
137 |
138 | #ifndef DEBUGINATOR_QUEUE_memcpy
139 | #include
140 | #define DEBUGINATOR_QUEUE_memcpy memcpy
141 | #endif
142 |
143 | #ifndef DEBUGINATOR_QUEUE_strcpy_s
144 | #include
145 | #define DEBUGINATOR_QUEUE_strcpy_s strcpy_s
146 | #endif
147 |
148 | static void
149 | debuginator_queue__ensure_capacity( TheDebuginatorQueue* queue ) {
150 | if ( queue->capacity + 1 == queue->num_items ) {
151 | int bytes = sizeof( DebuginatorQueueItem ) * queue->num_items * 2;
152 | void* items = queue->allocate( queue->userdata, bytes );
153 | DEBUGINATOR_QUEUE_memcpy( items, queue->items, bytes );
154 | queue->deallocate( queue->userdata, queue->items );
155 | queue->items = (DebuginatorQueueItem*)items;
156 | queue->capacity = queue->num_items * 2;
157 | }
158 | }
159 |
160 | // static const char*
161 | // debuginator_queue__copy_string( TheDebuginatorQueue* queue, const char* str ) {
162 | // int bytes = strlen( str );
163 | // void* buffer = queue->allocate( queue->userdata, bytes );
164 | // DEBUGINATOR_QUEUE_memcpy( buffer, str, bytes );
165 | // return (const char*)buffer;
166 | // }
167 |
168 | void
169 | debuginator_queue_clear( TheDebuginatorQueue* queue ) {
170 | // for ( int i_item = 0; i_item < queue->num_items; ++i_item ) {
171 | // DebuginatorQueueItem* item = &queue->items[i_item];
172 | // queue->cleanup_funcs[item->type]( queue, item );
173 | // }
174 | queue->num_items = 0;
175 | }
176 |
177 | unsigned char*
178 | debuginator_queue_data( TheDebuginatorQueue* queue, int* out_size ) {
179 | *out_size = queue->num_items * sizeof( DebuginatorQueueItem );
180 | return (unsigned char*)queue->items;
181 | }
182 |
183 | void
184 | debuginator_queue_create_bool_item( TheDebuginatorQueue* queue,
185 | const char* path,
186 | const char* description,
187 | void* userdata ) {
188 |
189 | debuginator_queue__ensure_capacity( queue );
190 |
191 | DebuginatorQueue_CreateItemData data;
192 | DEBUGINATOR_QUEUE_strcpy_s( data.path, DEBUGINATOR_QUEUE_MAX_PATH_LENGTH, path );
193 | DEBUGINATOR_QUEUE_strcpy_s(
194 | data.description, DEBUGINATOR_QUEUE_MAX_DESCRIPTION_LENGTH, description );
195 | data.userdata = userdata;
196 |
197 | DebuginatorQueueItem* item = &queue->items[queue->num_items++];
198 | item->type = DEBUGINATOR_QUEUE_CreateItem;
199 | item->data.create_item = data;
200 | }
201 |
202 | void
203 | debuginator_queue_create_bool_item_with_callback( TheDebuginatorQueue* queue,
204 | const char* path,
205 | const char* description,
206 | void* userdata,
207 | DebuginatorOnItemChangedCallback callback ) {
208 |
209 | debuginator_queue__ensure_capacity( queue );
210 |
211 | DebuginatorQueue_CreateItemData data;
212 | DEBUGINATOR_QUEUE_strcpy_s( data.path, DEBUGINATOR_QUEUE_MAX_PATH_LENGTH, path );
213 | DEBUGINATOR_QUEUE_strcpy_s(
214 | data.description, DEBUGINATOR_QUEUE_MAX_DESCRIPTION_LENGTH, description );
215 | data.userdata = userdata;
216 | data.callback = callback;
217 |
218 | DebuginatorQueueItem* item = &queue->items[queue->num_items++];
219 | item->type = DEBUGINATOR_QUEUE_CreateItem;
220 | item->data.create_item = data;
221 | }
222 |
223 | // void
224 | // debuginator_queue__create_bool_item_cleanup( TheDebuginatorQueue* queue,
225 | // DebuginatorQueueItem* item ) {
226 |
227 | // DebuginatorQueue_CreateItemData* data = (DebuginatorQueue_CreateItemData*)item->data;
228 | // queue->deallocate( queue->userdata, (void*)data->path );
229 | // queue->deallocate( queue->userdata, (void*)data->description );
230 | // queue->deallocate( queue->userdata, (void*)item->data );
231 | // }
232 |
233 | void
234 | debuginator_queue_process( const unsigned char* data, int size, TheDebuginator* debuginator ) {
235 | (void)( data, size, debuginator );
236 | #ifdef DEBUGINATOR_QUEUE_CAN_PROCEES
237 | const void* data_end = data + size;
238 | const DebuginatorQueueItem* item = (DebuginatorQueueItem*)(unsigned long long)data;
239 | while ( item < data_end ) {
240 | switch ( item->type ) {
241 | case DEBUGINATOR_QUEUE_CreateItem: {
242 | // debuginator_create_array_item(debuginator, NULL, item->data.create_item.path,
243 | // description, item->data.create_item.callback, item->data.create_item.userdata,
244 | // debuginator->bool_titles, debuginator->bool_values, 2,
245 | // sizeof(debuginator->bool_values[0]));
246 | if ( item->data.create_item.callback == NULL ) {
247 | debuginator_create_bool_item( debuginator,
248 | item->data.create_item.path,
249 | item->data.create_item.description,
250 | item->data.create_item.userdata );
251 | }
252 | else {
253 | debuginator_create_bool_item_with_callback( debuginator,
254 | item->data.create_item.path,
255 | item->data.create_item.description,
256 | item->data.create_item.userdata,
257 | item->data.create_item.callback );
258 | }
259 | } break;
260 | default:
261 | break;
262 | }
263 |
264 | item++;
265 | }
266 |
267 | DEBUGINATOR_QUEUE_assert( item == data_end );
268 | #endif
269 | }
270 |
271 | TheDebuginatorQueue*
272 | debuginator_queue_create( int initial_size,
273 | DebuginatorQueueAllocateFunc allocate_func,
274 | DebuginatorQueueDellocateFunc deallocate_func,
275 | void* userdata ) {
276 |
277 | int buffer_bytes = sizeof( TheDebuginatorQueue );
278 | int item_bytes = sizeof( DebuginatorQueueItem ) * initial_size;
279 | void* queue_buffer = allocate_func( userdata, buffer_bytes );
280 | void* item_buffer = allocate_func( userdata, item_bytes );
281 | TheDebuginatorQueue* queue = (TheDebuginatorQueue*)queue_buffer;
282 | queue->num_items = 0;
283 | queue->capacity = initial_size;
284 | queue->userdata = userdata;
285 | queue->allocate = allocate_func;
286 | queue->deallocate = deallocate_func;
287 | queue->items = (DebuginatorQueueItem*)item_buffer;
288 |
289 | // queue->cleanup_funcs[DEBUGINATOR_QUEUE_CreateItem] =
290 | // debuginator_queue__create_bool_item_cleanup;
291 |
292 | return queue;
293 | }
294 |
295 | #endif // DEBUGINATOR_QUEUE_IMPLEMENTATION
296 |
297 | #ifndef DEBUGINATOR_ENABLE_WARNINGS
298 | #ifdef _MSC_VER
299 | #pragma warning( pop )
300 | #endif
301 |
302 | #ifdef __clang__
303 | #pragma clang diagnostic pop
304 | #endif
305 | #endif
306 |
307 | #endif // INCLUDE_THE_DEBUGINATOR_H
308 |
309 | /*
310 | ------------------------------------------------------------------------------
311 | This software is available under 2 licenses -- choose whichever you prefer.
312 | ------------------------------------------------------------------------------
313 | ALTERNATIVE A - MIT License
314 | Copyright (c) 2017 Anders Elfgren
315 | Permission is hereby granted, free of charge, to any person obtaining a copy of
316 | this software and associated documentation files (the "Software"), to deal in
317 | the Software without restriction, including without limitation the rights to
318 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
319 | of the Software, and to permit persons to whom the Software is furnished to do
320 | so, subject to the following conditions:
321 | The above copyright notice and this permission notice shall be included in all
322 | copies or substantial portions of the Software.
323 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
324 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
325 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
326 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
327 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
328 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
329 | SOFTWARE.
330 | ------------------------------------------------------------------------------
331 | ALTERNATIVE B - Public Domain (www.unlicense.org)
332 | This is free and unencumbered software released into the public domain.
333 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
334 | software, either in source code form or as a compiled binary, for any purpose,
335 | commercial or non-commercial, and by any means.
336 | In jurisdictions that recognize copyright laws, the author or authors of this
337 | software dedicate any and all copyright interest in the software to the public
338 | domain. We make this dedication for the benefit of the public at large and to
339 | the detriment of our heirs and successors. We intend this dedication to be an
340 | overt act of relinquishment in perpetuity of all present and future rights to
341 | this software under copyright law.
342 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
343 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
344 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
345 | AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
346 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
347 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
348 | ------------------------------------------------------------------------------
349 | */
350 |
--------------------------------------------------------------------------------
/tools/stub_gen.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 |
4 | class Param:
5 | def __init__(self):
6 | self.type = None
7 | self.name = None
8 | def __repr__(self):
9 | # return "%s %s" % (self.type, self.name)
10 | return "%s" % (self.type)
11 |
12 |
13 | class Function:
14 | def __init__(self):
15 | self.return_type = None
16 | self.name = None
17 | self.params = []
18 | def __repr__(self):
19 | return "%-20s %-50s(%s) {}" % (self.return_type, self.name, ", ".join([str(p) for p in self.params]))
20 |
21 | if __name__ == "__main__":
22 |
23 | os.chdir(os.path.dirname(sys.argv[0]))
24 | functions = []
25 |
26 | with open("../the_debuginator.h") as file:
27 | state = "finding_start"
28 | curr_func = None
29 | for line in file:
30 | line = line.strip()
31 | if state == "finding_start":
32 | if "API START" in line:
33 | state = "parsing_api"
34 | elif state == "parsing_api":
35 | if "API END" in line:
36 | break
37 | if line == "":
38 | continue
39 | if line[:2] == "//":
40 | continue
41 |
42 | if curr_func == None:
43 | curr_func = Function()
44 | firstsplit = line.find(" ")
45 | curr_func.return_type = line[:firstsplit]
46 | parambegin = line.find("(", firstsplit)
47 | curr_func.name = line[firstsplit + 1:parambegin]
48 | parambegin += 1
49 |
50 | while True:
51 | type_end = line.find(" ", parambegin)
52 | p = Param()
53 | p.type = line[parambegin:type_end]
54 | name_begin = type_end + 1
55 | name_end = line.find(",", name_begin)
56 | if name_end == -1:
57 | name_end = line.find(")", name_begin)
58 | p.name = line[name_begin:name_end]
59 | curr_func.params.append(p)
60 |
61 | if name_end == -1:
62 | break
63 |
64 | if line[name_end:] == ",":
65 | break
66 |
67 | parambegin = name_end + 2
68 |
69 | if line[name_end:] == ");":
70 | print(curr_func)
71 | functions.append(curr_func)
72 | curr_func = None
73 | break
74 |
75 | # for f in functions:
76 | # print(f.name)
77 |
78 |
--------------------------------------------------------------------------------