├── .clang-format
├── .github
└── workflows
│ └── build.yaml
├── .gitignore
├── .vscode
├── c_cpp_properties.json
├── launch.json
├── settings.json
└── tasks.json
├── .zed
└── settings.json
├── ARCHITECTURE.md
├── LICENSE
├── README.md
├── assets
├── 04_paper-C-grain.webp
├── Grenze-Light.ttf
├── Grenze-Regular.ttf
├── Grenze-SemiBold.ttf
├── Grenze-Thin.ttf
├── NotoSans[wght].ttf
├── SFX
│ ├── button_down.wav
│ ├── button_up.wav
│ ├── cable_click.wav
│ ├── cable_end.wav
│ ├── cable_loop.wav
│ ├── cable_start.wav
│ ├── canvas_drop.wav
│ ├── canvas_pick.wav
│ ├── key_down.wav
│ ├── key_up.wav
│ ├── macro_start.wav
│ ├── macro_stop.wav
│ ├── mouse_down.wav
│ ├── mouse_up.wav
│ ├── next.wav
│ ├── toolbar_pick.wav
│ ├── toolbar_select_01.wav
│ ├── toolbar_select_02.wav
│ ├── toolbar_select_03.wav
│ └── trash.wav
├── anchor_warp_rt.sksl
├── assembler_stars_rt.sksl
├── automat_state.json
├── bubble_menu_rt.sksl
├── cable-weave-color.webp
├── cable-weave-normal.webp
├── cable_rt_sksl
├── card-reverse.webp
├── carpet.webp
├── connector_case_rt.sksl
├── connector_insert_rt.sksl
├── connector_rubber_rt.sksl
├── eng.traineddata
├── flag-cf.webp
├── flag-of.webp
├── flag.webp
├── flip-flop-color.webp
├── glitch_rt.sksl
├── heavy_data.ttf
├── helsinki.ttf
├── leaf.webp
├── macro-recorder-front-color.webp
├── mouse-base.webp
├── mouse-lmb-mask.webp
├── mouse-rmb-mask.webp
├── pointing-hand-color.webp
├── pressing-hand-color.webp
├── reg-ax.webp
├── reg-bx.webp
├── reg-cx.webp
├── reg-di.webp
├── reg-dx.webp
├── reg-read.webp
├── reg-si.webp
├── reg-write.webp
├── rose-0.webp
├── rose-1.webp
├── rose-2.webp
├── rose-3.webp
├── rose-4.webp
├── rose-5.webp
├── rose-6.webp
├── rosewood-color.webp
├── sharingan-color.svg
├── skybox.webp
├── slkscr.ttf
├── stalk.png
├── tray.webp
└── venus.webp
├── docs
├── 411172__silverillusionist__liquid-drink.mp3
├── Audiowide.woff2
├── CNAME
├── Caveat.woff2
├── HomemadeApple.woff2
├── PixelifySans.woff2
├── arches.png
├── arrow.webp
├── assets
│ ├── 2024-01-24 09-54-03.webm
│ ├── Makefile
│ ├── favicon-1024x1024.png
│ ├── favicon-512x512.png
│ ├── output.webm
│ └── 電磁祭囃子 in NEO TOKYO 🏮 [A0VYsiMtrNE].m4a
├── bg.js
├── cable_playground.html
├── cable_playground.js
├── cup-down.flac
├── cup-up.flac
├── cups-1.5x.webp
├── cups-1x.webp
├── cups-2x.webp
├── design
│ ├── Assembler.md
│ ├── Background Events.md
│ ├── Deleting Objects.md
│ ├── Multithreading.md
│ ├── Release Process.md
│ ├── Serialization.md
│ ├── Signal-Based Machine Code Execution.md
│ ├── Single binary.md
│ └── customizing-automat.webp
├── eject.flac
├── favicon-16x16.png
├── favicon-32x32.png
├── floppy-blue-2x.webp
├── floppy-down.flac
├── floppy-insert.flac
├── floppy-up.flac
├── index.html
├── napkin-down.flac
├── napkin-up.flac
├── napkin.webp
├── noise.webp
├── notebook-bg-2x.webp
├── notebook-cover-2x.webp
├── notebook-down.flac
├── notebook-flip.flac
├── notebook-up.flac
├── page-1-2x.webp
├── page-2-2x.webp
├── page-3-2x.webp
├── page-4-2x.webp
├── player-down.flac
├── player-up.flac
├── privacy_policy.html
├── vhs-1x.webp
├── vhs-2x.webp
├── vhs-3x.webp
├── vhs-down.flac
├── vhs-insert.flac
├── vhs-up.flac
└── video_player-2x.webp
├── pyrightconfig.json
├── run.bat
├── run.py
├── run_py
├── __main__.py
├── args.py
├── autotools.py
├── build.py
├── cc_embed.py
├── clang.py
├── cmake.py
├── debian_deps.py
├── extension_helper.py
├── fs_utils.py
├── git.py
├── graph_printer.py
├── inotify.py
├── make.py
├── monitor_new_pids.py
├── ninja.py
├── src.py
├── windows.py
└── windows_deps.py
├── source_images
├── Arrow
│ └── Direction.xcf
└── Mouse
│ ├── 01 Civitai Base.jpeg
│ ├── 02 Slight Variation Fooocus.png
│ ├── 03 Inpaint Cable Button.png
│ ├── 04 Inpaint Rest.png
│ ├── 05 Clipdrop Transparency.png
│ └── 06 - GIMP.xcf
├── src
├── action.hh
├── algebra.cc
├── algebra.hh
├── animation.cc
├── animation.hh
├── arcline.cc
├── arcline.hh
├── arcline_test.cc
├── argument.cc
├── argument.hh
├── arr.hh
├── audio.cc
├── audio.hh
├── automat.cc
├── automat.hh
├── backtrace.cc
├── backtrace.hh
├── base.cc
├── base.hh
├── blockingconcurrentqueue.hh
├── cavalier_contours.py
├── channel.hh
├── channel_test.cc
├── color.cc
├── color.hh
├── complex_test.cc
├── concurrentqueue.hh
├── connection.cc
├── connection.hh
├── connector_optical.cc
├── connector_optical.hh
├── control_flow.hh
├── dec64.cc
├── dec64.hh
├── dec64_test.cc
├── demo_static_vulkan_crash.cc
├── deserializer.cc
├── deserializer.hh
├── dev_actions.py
├── drag_action.cc
├── drag_action.hh
├── drawable.cc
├── drawable.hh
├── drawable_rtti.cc
├── drawable_rtti.hh
├── drawing.cc
├── drawing.hh
├── embedded.hh
├── embedded.py
├── error.cc
├── error.hh
├── fasttrigo.py
├── fn.hh
├── font.cc
├── font.hh
├── format.cc
├── format.hh
├── global_resources.cc
├── global_resources.hh
├── gtest.cc
├── gtest.hh
├── gtest.py
├── gui_button.cc
├── gui_button.hh
├── gui_connection_widget.cc
├── gui_connection_widget.hh
├── gui_constants.hh
├── gui_shape_widget.cc
├── gui_shape_widget.hh
├── gui_small_buffer_widget.cc
├── gui_small_buffer_widget.hh
├── gui_text.cc
├── gui_text.hh
├── hex.cc
├── hex.hh
├── hid.cc
├── hid.hh
├── hidapi.c
├── hidapi.h
├── hidapi_cfgmgr32.h
├── hidapi_descriptor_reconstruct.c
├── hidapi_descriptor_reconstruct.h
├── hidapi_hidclass.h
├── hidapi_hidpi.h
├── hidapi_hidsdi.h
├── hidapi_winapi.h
├── int.hh
├── key.cc
├── key.hh
├── key_button.cc
├── key_button.hh
├── keyboard.cc
├── keyboard.hh
├── knob.cc
├── knob.hh
├── leptonica.py
├── library.cc
├── library.hh
├── library_alert.cc
├── library_alert.hh
├── library_assembler.cc
├── library_assembler.hh
├── library_flip_flop.cc
├── library_flip_flop.hh
├── library_hotkey.cc
├── library_hotkey.hh
├── library_increment.cc
├── library_increment.hh
├── library_instruction.cc
├── library_instruction.hh
├── library_instruction_library.cc
├── library_instruction_library.hh
├── library_key_presser.cc
├── library_key_presser.hh
├── library_macro_recorder.cc
├── library_macro_recorder.hh
├── library_mouse_click.cc
├── library_mouse_click.hh
├── library_number.cc
├── library_number.hh
├── library_test.cc
├── library_timeline.cc
├── library_timeline.hh
├── library_timer.cc
├── library_timer.hh
├── library_toolbar.cc
├── library_toolbar.hh
├── library_window.cc
├── library_window.hh
├── lightweightsemaphore.hh
├── linux_hidapi.c
├── list_test.cc
├── llvm.py
├── llvm_asm.cc
├── llvm_asm.hh
├── llvm_asm.py
├── llvm_asm_test.cc
├── llvm_test.cc
├── loading_animation.cc
├── loading_animation.hh
├── location.cc
├── location.hh
├── log.cc
├── log.hh
├── log_skia.cc
├── log_skia.hh
├── machine_code.cc
├── machine_code.hh
├── manifest.rc
├── manifest.xml
├── math.cc
├── math.hh
├── math_constants.hh
├── menu.cc
├── menu.hh
├── number_text_field.cc
├── number_text_field.hh
├── object.cc
├── object.hh
├── on_off.hh
├── optional.hh
├── path.cc
├── path.hh
├── persistence.cc
├── persistence.hh
├── pipewire.py
├── pointer.cc
├── pointer.hh
├── prototypes.cc
├── prototypes.hh
├── ptr.hh
├── ptr_test.cc
├── random.cc
├── random.hh
├── rapidjson.py
├── release.py
├── release.service
├── release.timer
├── renderer.cc
├── renderer.hh
├── renderer_test.cc
├── root_widget.cc
├── root_widget.hh
├── run_button.cc
├── run_button.hh
├── seven_gui_test.cc
├── shared_or_weak.hh
├── sincos.cc
├── sincos.hh
├── sincos_test.cc
├── skia.py
├── span.hh
├── status.cc
├── status.hh
├── str.cc
├── str.hh
├── string_multimap.hh
├── svg.cc
├── svg.hh
├── tasks.cc
├── tasks.hh
├── template.hh
├── term.hh
├── tesseract.py
├── test_base.hh
├── text_field.cc
├── text_field.hh
├── textures.cc
├── textures.hh
├── theme_xp.cc
├── theme_xp.hh
├── thread_name.cc
├── thread_name.hh
├── threading_prototype.cc
├── time.cc
├── time.hh
├── timer_thread.cc
├── timer_thread.hh
├── touchpad.cc
├── touchpad.hh
├── tree_algorithms.hh
├── treemath.cc
├── treemath.hh
├── units.hh
├── vec.hh
├── virtual_fs.cc
├── virtual_fs.hh
├── vk.cc
├── vk.hh
├── vk_bootstrap.py
├── vulkan.py
├── wave1d.cc
├── wave1d.hh
├── widget.cc
├── widget.hh
├── win32.cc
├── win32.hh
├── win32_window.cc
├── win32_window.hh
├── win_hidapi.c
├── win_key.cc
├── win_key.hh
├── window.cc
├── window.hh
├── x11.cc
├── x11.hh
├── xcb.cc
├── xcb.hh
├── xcb.py
├── xcb_window.cc
├── xcb_window.hh
└── xkbcommon.py
├── tests
├── event_bench.json
├── event_bench.py
├── event_bench_log.json
├── perf_bench.json
└── perf_bench.py
└── third_party
├── FastTrigo
├── LICENSE
├── README.md
├── fasttrigo.cpp
└── fasttrigo.h
└── cavalier_contours
├── .clang-format
├── .gitignore
├── CMakeLists.txt
├── LICENSE
├── README.md
├── c_api_include
└── cavaliercontours.h
├── examples
├── CMakeLists.txt
├── basicpolylinefunctions.cpp
├── polylinecombine.cpp
├── polylineoffset.cpp
├── polylineoffsetislands.cpp
└── windingnumber.cpp
├── include
└── cavc
│ ├── internal
│ ├── common.hpp
│ └── diagnostics.hpp
│ ├── intrcircle2circle2.hpp
│ ├── intrlineseg2circle2.hpp
│ ├── intrlineseg2lineseg2.hpp
│ ├── mathutils.hpp
│ ├── plinesegment.hpp
│ ├── polyline.hpp
│ ├── polylinecombine.hpp
│ ├── polylineintersects.hpp
│ ├── polylineoffset.hpp
│ ├── polylineoffsetislands.hpp
│ ├── staticspatialindex.hpp
│ ├── vector.hpp
│ └── vector2.hpp
├── src
└── cavaliercontours.cpp
└── tests
├── CMakeLists.txt
├── benchmarks
├── CMakeLists.txt
├── areabenchmarks.cpp
├── benchmarkprofiles.h
├── clipper.cmake
├── clipperbenchmarks.cpp
├── combinebenchmarks.cpp
├── extentsbenchmarks.cpp
├── offsetbenchmarks.cpp
├── pathlengthbenchmarks.cpp
├── spatialindexbenchmarks.cpp
└── windingnumberbenchmarks.cpp
├── polylinefactory
├── CMakeLists.txt
├── include
│ └── polylinefactory.hpp
└── src
│ └── polylinefactory.cpp
└── tests
├── CMakeLists.txt
├── TEST_cavc_combine_plines.cpp
├── TEST_cavc_parallel_offset.cpp
├── TEST_cavc_pline.cpp
├── TEST_cavc_pline_function.cpp
├── TEST_sample.cpp
├── TEST_staticspatialindex.cpp
├── c_api_test_helpers.hpp
└── testhelpers.hpp
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | BasedOnStyle: Google
3 | ColumnLimit: 100
4 | ---
5 | Language: Cpp
6 | # Force pointers to the type for C++.
7 | DerivePointerAlignment: false
8 | PointerAlignment: Left
9 | ---
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | __pycache__
35 | .cache
36 | *.pyc
37 |
38 | *.log
39 | *.pcap
40 | *.pdb
41 |
42 | *~
43 |
44 | build
45 | third_party/*
46 | !third_party/FastTrigo
47 | !third_party/cavalier_contours
48 |
49 | tmp
50 |
51 | .gdb_history
52 |
53 | tests/dhclient
54 | tests/dhclient.pid
55 |
56 | source_images
57 |
58 | compile_commands.json
59 |
60 | www/assets
61 | www/builds
62 |
63 | perf.data
64 | perf.data.old
65 | palette.map
66 |
--------------------------------------------------------------------------------
/.vscode/c_cpp_properties.json:
--------------------------------------------------------------------------------
1 | {
2 | "configurations": [
3 | {
4 | "name": "Linux",
5 | "includePath": [
6 | "${workspaceFolder}/**"
7 | ],
8 | "defines": [],
9 | "compilerPath": "/usr/lib/llvm/18/bin/clang++",
10 | "cStandard": "gnu23",
11 | "cppStandard": "gnu++23",
12 | "compileCommands": "${workspaceFolder}/compile_commands.json"
13 | }
14 | ],
15 | "version": 4
16 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.analysis.extraPaths": [
3 | "./run_py"
4 | ],
5 | "cmake.configureOnOpen": false,
6 | "editor.formatOnSave": true
7 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "tasks": [
6 | {
7 | "label": "link current file",
8 | "type": "shell",
9 | "command": "python run.py 'link ${fileBasenameNoExtension}'",
10 | "presentation": {
11 | "reveal": "silent"
12 | }
13 | },
14 | {
15 | "label": "link current file debug",
16 | "type": "shell",
17 | "command": "python run.py 'link debug_${fileBasenameNoExtension}'",
18 | "presentation": {
19 | "reveal": "silent"
20 | }
21 | },
22 | {
23 | "label": "link debug_automat",
24 | "type": "shell",
25 | "command": "python run.py 'link debug_automat'",
26 | "presentation": {
27 | "reveal": "silent",
28 | "close": true
29 | }
30 | },
31 | {
32 | "label": "link automat",
33 | "type": "shell",
34 | "command": "python run.py 'link automat'",
35 | "presentation": {
36 | "reveal": "silent",
37 | "close": true
38 | }
39 | },
40 | ],
41 | }
--------------------------------------------------------------------------------
/.zed/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "tab_size": 2,
3 | "lsp": {
4 | "pyright": {
5 | "settings": {
6 | "python.analysis": {
7 | "diagnosticMode": "workspace",
8 | "typeCheckingMode": "strict",
9 | "extraPaths": ["./src", "./run_py"]
10 | }
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2024 Automat Authors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/assets/04_paper-C-grain.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/04_paper-C-grain.webp
--------------------------------------------------------------------------------
/assets/Grenze-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/Grenze-Light.ttf
--------------------------------------------------------------------------------
/assets/Grenze-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/Grenze-Regular.ttf
--------------------------------------------------------------------------------
/assets/Grenze-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/Grenze-SemiBold.ttf
--------------------------------------------------------------------------------
/assets/Grenze-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/Grenze-Thin.ttf
--------------------------------------------------------------------------------
/assets/NotoSans[wght].ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/NotoSans[wght].ttf
--------------------------------------------------------------------------------
/assets/SFX/button_down.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/button_down.wav
--------------------------------------------------------------------------------
/assets/SFX/button_up.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/button_up.wav
--------------------------------------------------------------------------------
/assets/SFX/cable_click.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/cable_click.wav
--------------------------------------------------------------------------------
/assets/SFX/cable_end.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/cable_end.wav
--------------------------------------------------------------------------------
/assets/SFX/cable_loop.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/cable_loop.wav
--------------------------------------------------------------------------------
/assets/SFX/cable_start.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/cable_start.wav
--------------------------------------------------------------------------------
/assets/SFX/canvas_drop.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/canvas_drop.wav
--------------------------------------------------------------------------------
/assets/SFX/canvas_pick.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/canvas_pick.wav
--------------------------------------------------------------------------------
/assets/SFX/key_down.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/key_down.wav
--------------------------------------------------------------------------------
/assets/SFX/key_up.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/key_up.wav
--------------------------------------------------------------------------------
/assets/SFX/macro_start.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/macro_start.wav
--------------------------------------------------------------------------------
/assets/SFX/macro_stop.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/macro_stop.wav
--------------------------------------------------------------------------------
/assets/SFX/mouse_down.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/mouse_down.wav
--------------------------------------------------------------------------------
/assets/SFX/mouse_up.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/mouse_up.wav
--------------------------------------------------------------------------------
/assets/SFX/next.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/next.wav
--------------------------------------------------------------------------------
/assets/SFX/toolbar_pick.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/toolbar_pick.wav
--------------------------------------------------------------------------------
/assets/SFX/toolbar_select_01.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/toolbar_select_01.wav
--------------------------------------------------------------------------------
/assets/SFX/toolbar_select_02.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/toolbar_select_02.wav
--------------------------------------------------------------------------------
/assets/SFX/toolbar_select_03.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/toolbar_select_03.wav
--------------------------------------------------------------------------------
/assets/SFX/trash.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/SFX/trash.wav
--------------------------------------------------------------------------------
/assets/automat_state.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 2,
3 | "window": {
4 | "maximized": {
5 | "horizontally": false,
6 | "vertically": false
7 | },
8 | "output_device_x": 0.002333,
9 | "output_device_y": 0.010759,
10 | "width": 0.231259,
11 | "height": 0.145444,
12 | "camera": {
13 | "x": -0.007981,
14 | "y": 0.002341,
15 | "zoom": 0.999998
16 | }
17 | },
18 | "root": {
19 | "name": "Root machine",
20 | "locations": {}
21 | }
22 | }
--------------------------------------------------------------------------------
/assets/cable-weave-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/cable-weave-color.webp
--------------------------------------------------------------------------------
/assets/cable-weave-normal.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/cable-weave-normal.webp
--------------------------------------------------------------------------------
/assets/cable_rt_sksl:
--------------------------------------------------------------------------------
1 | // kind=shader
2 |
3 | const float PI = 3.1415926535897932384626433832795;
4 |
5 | uniform shader cable_color;
6 | uniform shader cable_normal;
7 |
8 | float3x3 transpose3x3(in float3x3 inMatrix) {
9 | float3 i0 = inMatrix[0];
10 | float3 i1 = inMatrix[1];
11 | float3 i2 = inMatrix[2];
12 |
13 | float3x3 outMatrix = float3x3(
14 | float3(i0.x, i1.x, i2.x),
15 | float3(i0.y, i1.y, i2.y),
16 | float3(i0.z, i1.z, i2.z)
17 | );
18 |
19 | return outMatrix;
20 | }
21 |
22 | float4 main(vec2 uv) {
23 | vec3 lightDir = normalize(vec3(0, 1, 1)); // normalized vector pointing from current fragment towards the light
24 | float h = sqrt(1 - uv.x * uv.x );
25 | float angle = acos(uv.x);
26 |
27 | vec2 uv_x = vec2(dFdy(uv.x), dFdx(uv.x));
28 | float cable_width = 2 / length(uv_x);
29 |
30 | vec3 T = vec3(normalize(uv_x), 0);
31 | vec3 N = normalize(vec3(uv.x * T.y, -uv.x * T.x, h));
32 | vec3 B = cross(T, N);
33 | float3x3 TBN = float3x3(T, B, N);
34 | float3x3 TBN_inv = transpose3x3(TBN);
35 |
36 | vec2 texCoord = vec2(-angle / PI, uv.y / cable_width / 2) * 512;
37 |
38 | vec3 normalTanSpace = normalize(cable_normal.eval(texCoord).yxz * 2 - 1 + vec3(0, 0, 0.5)); // already in tangent space
39 | normalTanSpace.x = -normalTanSpace.x;
40 | vec3 lightDirTanSpace = normalize(TBN_inv * lightDir);
41 | vec3 viewDirTanSpace = normalize(TBN_inv * vec3(0, 0, 1));
42 |
43 | vec3 normal = normalize(TBN * normalTanSpace);
44 |
45 | vec4 color;
46 | color.rgba = cable_color.eval(texCoord).rgba;
47 | float light = min(1, 0.2 + max(dot(normalTanSpace, lightDirTanSpace), 0));
48 | color.rgb = light * color.rgb;
49 |
50 | color.rgb += pow(length(normal.xy), 8) * vec3(0.9, 0.9, 0.9) * 0.5; // rim lighting
51 |
52 | color.rgb += pow(max(dot(reflect(-lightDirTanSpace, normalTanSpace), viewDirTanSpace), 0), 10) * vec3(0.4, 0.4, 0.35);
53 |
54 | // color.r = uv.x * 0.5 + 0.5;
55 | // color.g = uv.y * 10;
56 | // color.b = 0;
57 | // color.a = 1;
58 | return color;
59 | }
--------------------------------------------------------------------------------
/assets/card-reverse.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/card-reverse.webp
--------------------------------------------------------------------------------
/assets/carpet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/carpet.webp
--------------------------------------------------------------------------------
/assets/connector_insert_rt.sksl:
--------------------------------------------------------------------------------
1 | // kind=shader
2 |
3 | const float kCaseSideRadius = 0.08;
4 | // NOTE: fix this once Skia supports array initializers here
5 | const vec3 kCaseBorderDarkColor = vec3(0x38, 0x36, 0x33) / 255; // subtle dark contour
6 | const vec3 kCaseBorderReflectionColor = vec3(0xdd, 0xdb, 0xd6) / 255; // canvas reflection
7 | const vec3 kCaseSideDarkColor = vec3(0x54, 0x51, 0x4e) / 255; // darker metal between reflections
8 | const vec3 kCaseFrontColor = vec3(0x85, 0x83, 0x80) / 255; // front color
9 | const float kBorderDarkWidth = 0.3;
10 | const float kCaseSideDarkH = 0.7;
11 | const float kCaseFrontH = 1;
12 | const vec3 kTopLightColor = vec3(0x32, 0x34, 0x39) / 255 - kCaseFrontColor;
13 | const float kBevelRadius = kBorderDarkWidth * kCaseSideRadius;
14 |
15 | vec4 main(vec2 uv) {
16 | float2 h = sin(min((0.5 - abs(0.5 - uv)) / kCaseSideRadius, 1) * 3.14159265358979323846 / 2);
17 | float bevel = 1 - length(1 - sin(min((0.5 - abs(0.5 - uv)) / kBevelRadius, 1) * 3.14159265358979323846 / 2));
18 | vec4 color;
19 | if (h.x < kCaseSideDarkH) {
20 | color.rgb = mix(kCaseBorderReflectionColor, kCaseSideDarkColor, (h.x - kBorderDarkWidth) / (kCaseSideDarkH - kBorderDarkWidth));
21 | } else {
22 | color.rgb = mix(kCaseSideDarkColor, kCaseFrontColor, (h.x - kCaseSideDarkH) / (kCaseFrontH - kCaseSideDarkH));
23 | }
24 | if (bevel < 1) {
25 | vec3 edge_color = kCaseBorderDarkColor;
26 | if (uv.y > 0.5) {
27 | edge_color = mix(edge_color, vec3(0.4), clamp((h.x - kCaseSideDarkH) / (kCaseFrontH - kCaseSideDarkH), 0, 1));
28 | }
29 | color.rgb = mix(edge_color, color.rgb, bevel);
30 | }
31 | color.a = 1;
32 | // Make the corners transparent
33 | vec2 grad_y = dFdy(uv);
34 | float plug_width_pixels = 1/length(grad_y);
35 | float radius_pixels = kBevelRadius * plug_width_pixels;
36 | color.rgba *= clamp(bevel * max(radius_pixels / 2, 1), 0, 1);
37 | return color;
38 | }
39 |
--------------------------------------------------------------------------------
/assets/eng.traineddata:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/eng.traineddata
--------------------------------------------------------------------------------
/assets/flag-cf.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/flag-cf.webp
--------------------------------------------------------------------------------
/assets/flag-of.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/flag-of.webp
--------------------------------------------------------------------------------
/assets/flag.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/flag.webp
--------------------------------------------------------------------------------
/assets/flip-flop-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/flip-flop-color.webp
--------------------------------------------------------------------------------
/assets/glitch_rt.sksl:
--------------------------------------------------------------------------------
1 | // kind=shader
2 |
3 | uniform shader surface;
4 | uniform float2 surfaceResolution; // size of the surface, in pixels
5 | uniform mat3 surfaceTransform;
6 | uniform float time;
7 |
8 | float hash(float n) {
9 | return fract(sin(n + time) * 43758.5453);
10 | }
11 |
12 | vec4 main(float2 localCoord) {
13 |
14 | float2 uv = (surfaceTransform * vec3(localCoord, 1)).xy;
15 | // return vec4(uv.x, uv.y, 0, 1);
16 | bool oob = false;
17 | float x_overshot = 0;
18 | float y_overshot = 0;
19 | if (uv.x > 1 || uv.x < 0) {
20 | oob = true;
21 | x_overshot = min(max(0, abs(uv.x - 0.5) - 0.5) / 2, 0.05);
22 | uv.x += hash(floor(uv.x * surfaceResolution.x / 10) / surfaceResolution.x) / 10;
23 | }
24 | if (uv.y > 1 || uv.y < 0) {
25 | oob = true;
26 | y_overshot = min(max(0, abs(uv.y - 0.5) - 0.5) / 2, 0.05);
27 | uv.y += hash(floor(uv.y * surfaceResolution.y / 10) / surfaceResolution.y) / 10;
28 | }
29 | if (oob) {
30 | uv.y += sin(uv.x * 4 + 2 * time * 2 * 3.14) * x_overshot;
31 | uv.x += sin(uv.y * 4 + 2 * time * 2 * 3.14) * y_overshot;
32 | }
33 | uv.y = 1 - uv.y;
34 | vec4 ret = surface.eval(uv * surfaceResolution);
35 | if (oob) {
36 | ret *= 0.5;
37 | ret *= hash(dot(uv, uv));
38 | }
39 | // Debug output: show similarity to some anchors
40 | // ret.r = similarity[0];
41 | // ret.g = similarity[1];
42 | return ret;
43 | }
44 |
--------------------------------------------------------------------------------
/assets/heavy_data.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/heavy_data.ttf
--------------------------------------------------------------------------------
/assets/helsinki.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/helsinki.ttf
--------------------------------------------------------------------------------
/assets/leaf.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/leaf.webp
--------------------------------------------------------------------------------
/assets/macro-recorder-front-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/macro-recorder-front-color.webp
--------------------------------------------------------------------------------
/assets/mouse-base.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/mouse-base.webp
--------------------------------------------------------------------------------
/assets/mouse-lmb-mask.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/mouse-lmb-mask.webp
--------------------------------------------------------------------------------
/assets/mouse-rmb-mask.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/mouse-rmb-mask.webp
--------------------------------------------------------------------------------
/assets/pointing-hand-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/pointing-hand-color.webp
--------------------------------------------------------------------------------
/assets/pressing-hand-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/pressing-hand-color.webp
--------------------------------------------------------------------------------
/assets/reg-ax.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-ax.webp
--------------------------------------------------------------------------------
/assets/reg-bx.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-bx.webp
--------------------------------------------------------------------------------
/assets/reg-cx.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-cx.webp
--------------------------------------------------------------------------------
/assets/reg-di.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-di.webp
--------------------------------------------------------------------------------
/assets/reg-dx.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-dx.webp
--------------------------------------------------------------------------------
/assets/reg-read.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-read.webp
--------------------------------------------------------------------------------
/assets/reg-si.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-si.webp
--------------------------------------------------------------------------------
/assets/reg-write.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/reg-write.webp
--------------------------------------------------------------------------------
/assets/rose-0.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-0.webp
--------------------------------------------------------------------------------
/assets/rose-1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-1.webp
--------------------------------------------------------------------------------
/assets/rose-2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-2.webp
--------------------------------------------------------------------------------
/assets/rose-3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-3.webp
--------------------------------------------------------------------------------
/assets/rose-4.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-4.webp
--------------------------------------------------------------------------------
/assets/rose-5.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-5.webp
--------------------------------------------------------------------------------
/assets/rose-6.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rose-6.webp
--------------------------------------------------------------------------------
/assets/rosewood-color.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/rosewood-color.webp
--------------------------------------------------------------------------------
/assets/skybox.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/skybox.webp
--------------------------------------------------------------------------------
/assets/slkscr.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/slkscr.ttf
--------------------------------------------------------------------------------
/assets/stalk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/stalk.png
--------------------------------------------------------------------------------
/assets/tray.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/tray.webp
--------------------------------------------------------------------------------
/assets/venus.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/assets/venus.webp
--------------------------------------------------------------------------------
/docs/411172__silverillusionist__liquid-drink.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/411172__silverillusionist__liquid-drink.mp3
--------------------------------------------------------------------------------
/docs/Audiowide.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/Audiowide.woff2
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | automat.org
--------------------------------------------------------------------------------
/docs/Caveat.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/Caveat.woff2
--------------------------------------------------------------------------------
/docs/HomemadeApple.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/HomemadeApple.woff2
--------------------------------------------------------------------------------
/docs/PixelifySans.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/PixelifySans.woff2
--------------------------------------------------------------------------------
/docs/arches.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/arches.png
--------------------------------------------------------------------------------
/docs/arrow.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/arrow.webp
--------------------------------------------------------------------------------
/docs/assets/2024-01-24 09-54-03.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/assets/2024-01-24 09-54-03.webm
--------------------------------------------------------------------------------
/docs/assets/Makefile:
--------------------------------------------------------------------------------
1 | output.webm:
2 | ffmpeg -i '2024-01-24 09-54-03.webm' -stream_loop -1 -i '電磁祭囃子 in NEO TOKYO 🏮 [A0VYsiMtrNE].m4a' -c:v copy -t 98s 'output.webm'
3 |
--------------------------------------------------------------------------------
/docs/assets/favicon-1024x1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/assets/favicon-1024x1024.png
--------------------------------------------------------------------------------
/docs/assets/favicon-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/assets/favicon-512x512.png
--------------------------------------------------------------------------------
/docs/assets/output.webm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/assets/output.webm
--------------------------------------------------------------------------------
/docs/assets/電磁祭囃子 in NEO TOKYO 🏮 [A0VYsiMtrNE].m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/assets/電磁祭囃子 in NEO TOKYO 🏮 [A0VYsiMtrNE].m4a
--------------------------------------------------------------------------------
/docs/cable_playground.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Automat Cable Playground
7 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/docs/cup-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/cup-down.flac
--------------------------------------------------------------------------------
/docs/cup-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/cup-up.flac
--------------------------------------------------------------------------------
/docs/cups-1.5x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/cups-1.5x.webp
--------------------------------------------------------------------------------
/docs/cups-1x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/cups-1x.webp
--------------------------------------------------------------------------------
/docs/cups-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/cups-2x.webp
--------------------------------------------------------------------------------
/docs/design/Deleting Objects.md:
--------------------------------------------------------------------------------
1 | # Object deletion in Automat
2 |
3 | A designated corner is going to be used as a drag target for deleting objects (Vlojure approach)
4 | Optionally also drag a trash icon onto the menu object to delete it
5 | Alternatively a dock object with edit mode or buttons to move & delete objects
6 | Alternatively drop objects outside of the canvas to delete them :P
7 |
8 | - excluding the solution with context menu
9 | - excluding the solution with "delete" button on every object
10 |
11 | 1. Pinning objects to the screen (they don't move with the camera)
12 | 2. Trash object that deletes all objects that are dragged over it
13 | 3. Trash grabber that can be grabbed to delete objects
14 |
15 | 4. A new "dock" object that holds the prototypes
16 | - buttons to delete and move prototypes around
17 | - "edit" mode when the dock can be altered (iOS approach)
18 |
--------------------------------------------------------------------------------
/docs/design/Serialization.md:
--------------------------------------------------------------------------------
1 | # Why don't Automat objects have UUIDs?
2 |
3 | This is because mutable objects are fuzzy (their boundaries can change, their identity is often defined by their context) and numerous. Tracking object identity involves a lot of work and creates many problems for pretty little gain. Instead of UUIDs, Automat objects are identified by their address in memory. When serialized, they're assigned short unique identifiers meant to identify them only within the context of their parent machine. Objects can also have names assigned by the user - they are very different and worth accurate tracking.
--------------------------------------------------------------------------------
/docs/design/customizing-automat.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/design/customizing-automat.webp
--------------------------------------------------------------------------------
/docs/eject.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/eject.flac
--------------------------------------------------------------------------------
/docs/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/floppy-blue-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/floppy-blue-2x.webp
--------------------------------------------------------------------------------
/docs/floppy-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/floppy-down.flac
--------------------------------------------------------------------------------
/docs/floppy-insert.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/floppy-insert.flac
--------------------------------------------------------------------------------
/docs/floppy-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/floppy-up.flac
--------------------------------------------------------------------------------
/docs/napkin-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/napkin-down.flac
--------------------------------------------------------------------------------
/docs/napkin-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/napkin-up.flac
--------------------------------------------------------------------------------
/docs/napkin.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/napkin.webp
--------------------------------------------------------------------------------
/docs/noise.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/noise.webp
--------------------------------------------------------------------------------
/docs/notebook-bg-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/notebook-bg-2x.webp
--------------------------------------------------------------------------------
/docs/notebook-cover-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/notebook-cover-2x.webp
--------------------------------------------------------------------------------
/docs/notebook-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/notebook-down.flac
--------------------------------------------------------------------------------
/docs/notebook-flip.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/notebook-flip.flac
--------------------------------------------------------------------------------
/docs/notebook-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/notebook-up.flac
--------------------------------------------------------------------------------
/docs/page-1-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/page-1-2x.webp
--------------------------------------------------------------------------------
/docs/page-2-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/page-2-2x.webp
--------------------------------------------------------------------------------
/docs/page-3-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/page-3-2x.webp
--------------------------------------------------------------------------------
/docs/page-4-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/page-4-2x.webp
--------------------------------------------------------------------------------
/docs/player-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/player-down.flac
--------------------------------------------------------------------------------
/docs/player-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/player-up.flac
--------------------------------------------------------------------------------
/docs/vhs-1x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-1x.webp
--------------------------------------------------------------------------------
/docs/vhs-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-2x.webp
--------------------------------------------------------------------------------
/docs/vhs-3x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-3x.webp
--------------------------------------------------------------------------------
/docs/vhs-down.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-down.flac
--------------------------------------------------------------------------------
/docs/vhs-insert.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-insert.flac
--------------------------------------------------------------------------------
/docs/vhs-up.flac:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/vhs-up.flac
--------------------------------------------------------------------------------
/docs/video_player-2x.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/docs/video_player-2x.webp
--------------------------------------------------------------------------------
/pyrightconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "src/**/*.py",
4 | "run_py/**/*.py"
5 | ],
6 | }
--------------------------------------------------------------------------------
/run.py:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env python3
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | # This file needs a .py suffix in order to run under Windows.
6 |
7 | import sys, os
8 | from subprocess import run
9 | from pathlib import Path
10 |
11 | base_dir = Path(__file__).parent
12 | exit_code = 0
13 | try:
14 | completed_process = run(['python', str(base_dir / 'run_py')] + sys.argv[1:], cwd=base_dir)
15 | exit_code = completed_process.returncode
16 | except KeyboardInterrupt:
17 | pass
18 | except Exception as e:
19 | print(e)
20 |
21 | # On Windows, if launched with double-click, keep
22 | # the window open until the user presses ENTER.
23 | #
24 | # Note: Temporarily disabled because it's not working with VSCode tasks.
25 | #
26 | # if os.name == 'nt' and 'PROMPT' not in os.environ:
27 | # input('Press ENTER to exit...')
28 |
29 | sys.exit(exit_code)
30 |
--------------------------------------------------------------------------------
/run_py/__main__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | '''Run Automat.'''
6 |
7 | from args import args
8 | from sys import platform, exit
9 |
10 | if platform == 'win32':
11 | import windows_deps
12 | windows_deps.check_and_install()
13 |
14 | import build
15 | import subprocess
16 |
17 | import debian_deps
18 | debian_deps.check_and_install()
19 |
20 |
21 | recipe = build.recipe()
22 |
23 |
24 | if args.verbose:
25 | import fs_utils
26 | import graph_printer
27 | graph_printer.print_graph(recipe, fs_utils.build_dir / 'graph.html')
28 | print('Build graph written to build/graph.html')
29 |
30 | if args.fresh:
31 | print('Cleaning old build results:')
32 | recipe.clean()
33 |
34 | active_recipe = None
35 |
36 | while True:
37 | recipe.set_target(args.target)
38 | if args.live:
39 | watcher = subprocess.Popen(
40 | ['python', 'run_py/inotify.py', 'src/', 'assets/'], stdout=subprocess.DEVNULL)
41 | else:
42 | watcher = None
43 |
44 | try:
45 | ok = recipe.execute(watcher)
46 | except KeyboardInterrupt:
47 | exit(2)
48 | if ok:
49 | if active_recipe:
50 | active_recipe.interrupt()
51 | active_recipe = recipe
52 | if watcher:
53 | try:
54 | print('Watching src/ for changes...')
55 | watcher.wait()
56 | except KeyboardInterrupt:
57 | watcher.kill()
58 | break
59 | else:
60 | break
61 | # Reload the recipe because dependencies may have changed
62 | recipe = build.recipe()
63 | if not ok:
64 | exit(1)
65 |
--------------------------------------------------------------------------------
/run_py/args.py:
--------------------------------------------------------------------------------
1 | '''Module with all of the command line flags used by the build script.'''
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | # TODO: allow different python modules to add their own args - instead of a centralized location. This should allow for better Hyperdeck / Automat reusability.
6 |
7 | import __main__
8 | import argparse
9 | import sys
10 |
11 | sys.argv[0] = 'run'
12 |
13 | parser = argparse.ArgumentParser(
14 | description=__main__.__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
15 | parser.add_argument('--fresh', action='store_true')
16 | parser.add_argument('--live', action='store_true')
17 | parser.add_argument('--verbose', action='store_true')
18 | parser.add_argument('target')
19 | parser.add_argument('-x', action='append',
20 | help='argument passed to the target', dest='extra_args', default=[])
21 | args = parser.parse_args()
22 |
--------------------------------------------------------------------------------
/run_py/cc_embed.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | import string
4 |
5 | byte_to_c_string_table = {c: chr(c) for c in range(32, 127)}
6 | byte_to_c_string_table[0x22] = '\\"'
7 | byte_to_c_string_table[0x5c] = '\\\\'
8 | byte_to_c_string_table[0x07] = '\\a'
9 | byte_to_c_string_table[0x08] = '\\b'
10 | byte_to_c_string_table[0x0c] = '\\f'
11 | byte_to_c_string_table[0x0a] = '\\n'
12 | byte_to_c_string_table[0x0d] = '\\r'
13 | byte_to_c_string_table[0x09] = '\\t'
14 | byte_to_c_string_table[0x0b] = '\\v'
15 |
16 | digit_bytes = set(ord(c) for c in string.digits)
17 |
18 |
19 | def byte_to_c_string(b, next_b=None):
20 | if b in byte_to_c_string_table:
21 | return byte_to_c_string_table[b]
22 | elif next_b in digit_bytes:
23 | return '\\' + format(b, '03o')
24 | else:
25 | return '\\' + format(b, 'o')
26 |
27 |
28 | def pairwise(iterable):
29 | it = iter(iterable)
30 | a = next(it)
31 | for b in it:
32 | yield a, b
33 | a = b
34 |
35 |
36 | def bytes_to_c_string(bytes):
37 | # x is a dummy byte
38 | return '"' + ''.join(byte_to_c_string(b, next_b) for b, next_b in pairwise(bytes + b'x')) + '"'
39 |
--------------------------------------------------------------------------------
/run_py/clang.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | import subprocess
4 | import shutil
5 | from glob import glob
6 | import re
7 |
8 | def natural_sort(l):
9 | convert = lambda text: int(text) if text.isdigit() else text.lower()
10 | alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)]
11 | return sorted(l, key=alphanum_key)
12 |
13 | if shutil.which('clang'):
14 | executable = 'clang++'
15 | executable_c = 'clang'
16 | else:
17 | clang_binaries = glob('/usr/lib/llvm/*/bin/clang')
18 | if clang_binaries:
19 | clang_binaries = natural_sort(clang_binaries)
20 | executable = clang_binaries[-1] + '++'
21 | executable_c = clang_binaries[-1]
22 | else:
23 | raise FileNotFoundError('Couldn\'t find `clang` program. Searched $PATH and `/usr/lib/llvm/*/bin/`.')
24 |
25 | def query_default_defines() -> set[str]:
26 | result = subprocess.run([executable, '-dM', '-E', '-'],
27 | stdin=subprocess.DEVNULL, stdout=subprocess.PIPE)
28 | return set([line.split()[1] for line in result.stdout.decode().splitlines()])
29 |
30 |
31 | default_defines = query_default_defines()
32 |
--------------------------------------------------------------------------------
/run_py/cmake.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | import build
4 | import ninja
5 |
6 | build.fast.CMAKE_BUILD_TYPE = 'RelWithDebInfo'
7 | build.release.CMAKE_BUILD_TYPE = 'Release'
8 | build.debug.CMAKE_BUILD_TYPE = 'Debug'
9 |
10 | build.fast.CMAKE_MSVC_RUNTIME_LIBRARY = 'MultiThreaded'
11 | build.release.CMAKE_MSVC_RUNTIME_LIBRARY = 'MultiThreaded'
12 | build.debug.CMAKE_MSVC_RUNTIME_LIBRARY = 'MultiThreadedDebug'
13 |
14 | def CMakeArgs(build_type: build.BuildType, extra_defines: dict[str, str] = {}):
15 | CMAKE_BUILD_TYPE = build_type.CMAKE_BUILD_TYPE
16 | CMAKE_MSVC_RUNTIME_LIBRARY = build_type.CMAKE_MSVC_RUNTIME_LIBRARY
17 | CMAKE_MAKE_PROGRAM = str(ninja.BIN)
18 | CMAKE_INSTALL_LIBDIR = 'lib64'
19 |
20 | cmake_args = ['cmake', '-G', 'Ninja', f'-D{CMAKE_BUILD_TYPE=}', f'-D{CMAKE_MAKE_PROGRAM=}',
21 | f'-DCMAKE_C_COMPILER={build.compiler_c}', f'-DCMAKE_CXX_COMPILER={build.compiler}',
22 | f'-D{CMAKE_MSVC_RUNTIME_LIBRARY=}', f'-D{CMAKE_INSTALL_LIBDIR=}']
23 |
24 | cmake_args += ['-DCMAKE_INSTALL_PREFIX=' + str(build_type.PREFIX())]
25 |
26 | for name, value in extra_defines.items():
27 | cmake_args += ['-D' + name + '=' + value]
28 |
29 | return cmake_args
30 |
--------------------------------------------------------------------------------
/run_py/debian_deps.py:
--------------------------------------------------------------------------------
1 | '''This module ensures that all of the necessary Debian dependencies are installed.'''
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | import os
6 | from subprocess import run
7 | from sys import platform
8 |
9 | path_to_package = {
10 | "/usr/include/zlib.h": "zlib1g-dev",
11 | "/usr/include/openssl/ssl.h": "libssl-dev",
12 | "/usr/include/gmock": "libgmock-dev",
13 | "/usr/bin/meson": "meson",
14 | "/usr/include/X11/Xlib.h": "libx11-dev",
15 | "/usr/include/X11/extensions/Xrandr.h": "libxrandr-dev",
16 | "/usr/include/X11/extensions/Xinerama.h": "libxinerama-dev",
17 | "/usr/include/X11/Xcursor/Xcursor.h": "libxcursor-dev",
18 | "/usr/include/X11/extensions/XInput2.h": "libxi-dev",
19 | "/usr/include/GL/gl.h": "libgl-dev",
20 | "/usr/include/fontconfig/fontconfig.h": "libfontconfig-dev",
21 | }
22 |
23 |
24 | def check_and_install():
25 | if platform != 'linux':
26 | return
27 | missing_packages = set()
28 | for path, package in path_to_package.items():
29 | if not os.path.exists(path):
30 | missing_packages.add(package)
31 | if missing_packages:
32 | print("Some packages are missing from your system. Will try to install them automatically:\n")
33 | print(" ", ', '.join(missing_packages))
34 | print("In case of errors with clang or libc++ installation - add the repositories from https://apt.llvm.org/ and re-run this script.\n")
35 | print("Press enter to continue or Ctrl+C to cancel.")
36 | try:
37 | input()
38 | except EOFError:
39 | print("Got EOF - batch job detected. Continuing with the installation.")
40 | command = ["apt", "-y", "install"] + list(missing_packages)
41 | if os.geteuid() != 0: # non-root users need `sudo` to install stuff
42 | command = ["sudo"] + command
43 | print(" ".join(command) + "\n")
44 | run(command, check=True)
45 |
--------------------------------------------------------------------------------
/run_py/fs_utils.py:
--------------------------------------------------------------------------------
1 | '''Utilities for operating on filesystem.'''
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | from pathlib import Path
6 | from sys import platform
7 |
8 | project_root = Path(__file__).resolve().parents[1]
9 | project_name = Path(project_root).name.lower()
10 | build_dir = project_root / 'build'
11 | src_dir = project_root / 'src'
12 | generated_dir = project_root / 'build' / 'generated'
13 | third_party_dir = project_root / 'third_party'
14 | run_py_dir = project_root / 'run_py'
15 |
16 | binary_extension = '.exe' if platform == 'win32' else ''
--------------------------------------------------------------------------------
/run_py/git.py:
--------------------------------------------------------------------------------
1 | '''Utilities for working with git repositories.'''
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | from functools import partial
6 | import make
7 |
8 | def clone(url, out_directory, tag):
9 | '''Return an asynchronous 'git clone' wrapper.'''
10 | return partial(make.Popen, [
11 | 'git',
12 | '-c', 'advice.detachedHead=false',
13 | '-c', 'core.autocrlf=false',
14 | 'clone',
15 | '--depth', '1',
16 | '--branch', tag,
17 | url, out_directory])
18 |
--------------------------------------------------------------------------------
/run_py/graph_printer.py:
--------------------------------------------------------------------------------
1 | import fs_utils
2 | from pathlib import Path
3 |
4 | def short_path(path_str):
5 | path = Path(path_str)
6 | if path.is_relative_to(fs_utils.project_root):
7 | return str(path.relative_to(fs_utils.project_root))
8 | else:
9 | return path_str
10 |
11 | def print_graph(recipe, html_path):
12 | fs_utils.build_dir.mkdir(parents=True, exist_ok=True)
13 | file_to_step = {}
14 | for step in recipe.steps:
15 | for output in step.outputs:
16 | file_to_step[output] = step
17 | with open(html_path, 'w') as f:
18 | f.write('\n')
19 | for step in recipe.steps:
20 | f.write(f'{step.shortcut}
\n')
21 | f.write(f'{step.desc}
\n')
22 | f.write('Inputs: ')
23 | for inp in sorted(str(x) for x in step.inputs):
24 | inp_short = short_path(inp)
25 | if inp in file_to_step:
26 | input_step = file_to_step[inp]
27 | f.write(f'{inp_short}')
28 | else:
29 | f.write(inp_short)
30 | f.write(', ')
31 | f.write('
\n')
32 | f.write('Outputs: ')
33 | for out in sorted(str(x) for x in step.outputs):
34 | f.write(short_path(out))
35 | f.write(', ')
36 | f.write('
\n')
37 | f.write('')
38 |
--------------------------------------------------------------------------------
/run_py/ninja.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | '''Rules for downloading the Ninja build system'''
4 |
5 | # TODO: move this to src/ and remove the empty hook_recipe function
6 |
7 | import shutil
8 | from pathlib import Path
9 |
10 | BIN_STR = shutil.which('ninja')
11 |
12 | if BIN_STR:
13 | BIN = Path(BIN_STR)
14 | def hook_recipe(recipe):
15 | pass
16 | else:
17 | print('Ninja not found - adding recipe to download it.')
18 |
19 | import build, sys, fs_utils
20 | if sys.platform == 'win32':
21 | ZIP_NAME = 'ninja-win.zip'
22 | elif sys.platform == 'darwin':
23 | ZIP_NAME = 'ninja-mac.zip'
24 | elif sys.platform == 'linux':
25 | ZIP_NAME = 'ninja-linux.zip'
26 | else:
27 | raise NotImplementedError(f'TODO: platform {sys.platform} is missing in ninja.py')
28 |
29 | DOWNLOAD_URL = 'https://github.com/ninja-build/ninja/releases/latest/download/' + ZIP_NAME
30 | ZIP_PATH = fs_utils.build_dir / ZIP_NAME
31 | BIN = build.base.PREFIX() / 'bin' / 'ninja'
32 |
33 | def download(url, out_path):
34 | import urllib.request, shutil
35 | with urllib.request.urlopen(url) as response:
36 | with open(out_path, 'wb') as out_file:
37 | shutil.copyfileobj(response, out_file)
38 |
39 | def download_step(url, out_path):
40 | import functools
41 | return functools.partial(download, url, out_path)
42 |
43 | def unzip(zip_path, out_dir):
44 | import zipfile
45 | with zipfile.ZipFile(zip_path, 'r') as zip_ref:
46 | zip_ref.extractall(out_dir)
47 |
48 | def unzip_step(zip_path, out_dir):
49 | import functools
50 | return functools.partial(unzip, zip_path, out_dir)
51 |
52 | def hook_recipe(recipe):
53 | recipe.add_step(
54 | download_step(DOWNLOAD_URL, ZIP_PATH),
55 | outputs=[ZIP_PATH],
56 | inputs=[],
57 | desc='Downloading Ninja',
58 | shortcut='download ninja')
59 |
60 | recipe.add_step(
61 | unzip_step(ZIP_PATH, BIN.parent),
62 | outputs=[BIN],
63 | inputs=[ZIP_PATH],
64 | desc='Unzipping Ninja',
65 | shortcut='unzip ninja')
66 |
--------------------------------------------------------------------------------
/run_py/windows.py:
--------------------------------------------------------------------------------
1 | ''' Utilities for working with Windows. '''
2 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
3 | # SPDX-License-Identifier: MIT
4 |
5 | import sys
6 |
7 | if sys.platform != 'win32':
8 | raise Exception('This module is only for Windows')
9 |
10 | import ctypes
11 |
12 | user32 = ctypes.windll.user32
13 | GetWindowThreadProcessId = user32.GetWindowThreadProcessId
14 | EnumWindows = user32.EnumWindows
15 | EnumWindowsProc = ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int))
16 | GetWindowText = user32.GetWindowTextW
17 | GetWindowTextLength = user32.GetWindowTextLengthW
18 | GetParent = user32.GetParent
19 | IsWindowVisible = user32.IsWindowVisible
20 |
21 |
22 | def is_main(hwnd):
23 | return GetParent(hwnd) == 0
24 |
25 |
26 | def is_visible(hwnd):
27 | return IsWindowVisible(hwnd)
28 |
29 |
30 | def get_pid(hwnd):
31 | pid = ctypes.c_ulong()
32 | GetWindowThreadProcessId(hwnd, ctypes.byref(pid))
33 | return pid.value
34 |
35 |
36 | '''Sends a WM_CLOSE message to the main window of the process with the given PID.
37 |
38 | Returns True if the window was found and WM_CLOSE sent, False otherwise.'''
39 | def close_window(pid):
40 | hwnds = []
41 | def foreach_window(hwnd, lParam):
42 | if not is_main(hwnd) or not is_visible(hwnd):
43 | return True
44 | # length = GetWindowTextLength(hwnd)
45 | # buff = ctypes.create_unicode_buffer(length + 1)
46 | # GetWindowText(hwnd, buff, length + 1)
47 | # hwnd_title = buff.value
48 | hwnd_pid = get_pid(hwnd)
49 | if pid == hwnd_pid:
50 | hwnds.append(hwnd)
51 | return True
52 | EnumWindows(EnumWindowsProc(foreach_window), 0)
53 | if len(hwnds) != 1:
54 | return False
55 | hwnd = hwnds[0]
56 | user32.PostMessageW(hwnd, 0x0010, 0, 0)
57 | return True
58 |
59 |
--------------------------------------------------------------------------------
/source_images/Arrow/Direction.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Arrow/Direction.xcf
--------------------------------------------------------------------------------
/source_images/Mouse/01 Civitai Base.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/01 Civitai Base.jpeg
--------------------------------------------------------------------------------
/source_images/Mouse/02 Slight Variation Fooocus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/02 Slight Variation Fooocus.png
--------------------------------------------------------------------------------
/source_images/Mouse/03 Inpaint Cable Button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/03 Inpaint Cable Button.png
--------------------------------------------------------------------------------
/source_images/Mouse/04 Inpaint Rest.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/04 Inpaint Rest.png
--------------------------------------------------------------------------------
/source_images/Mouse/05 Clipdrop Transparency.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/05 Clipdrop Transparency.png
--------------------------------------------------------------------------------
/source_images/Mouse/06 - GIMP.xcf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mafik/automat/1c946f2373fdb8ae8abac172353b92187d7d0bfa/source_images/Mouse/06 - GIMP.xcf
--------------------------------------------------------------------------------
/src/action.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | namespace automat {
6 |
7 | namespace gui {
8 | struct Pointer;
9 | struct Widget;
10 | } // namespace gui
11 |
12 | // Action represents an action/gesture that user can perform by pressing a key / button / touching
13 | // the screen and then moving the pointer around before releasing it.
14 | //
15 | // Actions are the main mechanism for user to interact with the UI.
16 | struct Action {
17 | gui::Pointer& pointer;
18 |
19 | // Each action must be bound to a pointer. A reference to the pointer is stored internally to keep
20 | // track of its position.
21 | Action(gui::Pointer& pointer) : pointer(pointer) {}
22 |
23 | // Action is destroyed when the pointer is released. This typically corresponds to the button
24 | // release or key up.
25 | virtual ~Action() = default;
26 |
27 | // Update is called when the pointer moves (although spurious calls are also possible). This
28 | // function may be called hundreds of times per second.
29 | virtual void Update() = 0;
30 |
31 | virtual gui::Widget* Widget() { return nullptr; }
32 | };
33 |
34 | struct EmptyAction : Action {
35 | EmptyAction(gui::Pointer& pointer) : Action(pointer) {}
36 | void Update() override {}
37 | };
38 |
39 | } // namespace automat
40 |
--------------------------------------------------------------------------------
/src/arr.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include
4 |
5 | namespace automat {
6 |
7 | template
8 | using Arr = std::array;
9 |
10 | } // namespace automat
--------------------------------------------------------------------------------
/src/audio.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include "virtual_fs.hh"
6 |
7 | namespace automat::audio {
8 |
9 | using Sound = fs::VFile;
10 |
11 | #ifdef __linux__
12 | void Init(int* argc, char*** argv);
13 | #else
14 | void Init();
15 | #endif
16 |
17 | void Stop();
18 |
19 | void Play(Sound&);
20 |
21 | struct Effect {
22 | virtual ~Effect() {}
23 | };
24 |
25 | std::unique_ptr MakeBeginLoopEndEffect(Sound& begin, Sound& loop, Sound& end);
26 |
27 | } // namespace automat::audio
--------------------------------------------------------------------------------
/src/automat.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 |
7 | #include "base.hh"
8 |
9 | // High-level automat code.
10 |
11 | namespace automat {
12 |
13 | extern std::stop_source stop_source;
14 | extern Ptr root_location;
15 | extern Ptr root_machine;
16 | extern std::jthread automat_thread;
17 | extern std::atomic_bool automat_thread_finished;
18 |
19 | extern std::thread::id main_thread_id;
20 |
21 | void StopAutomat(Status&);
22 |
23 | void EnqueueTask(Task* task);
24 | void RunOnAutomatThread(std::function);
25 | void RunOnAutomatThreadSynchronous(std::function);
26 | void AssertAutomatThread();
27 |
28 | void RunLoop(const int max_iterations = -1);
29 |
30 | } // namespace automat
--------------------------------------------------------------------------------
/src/backtrace.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | bool PrintBacktrace();
6 | void EnableBacktraceOnSIGSEGV();
7 |
--------------------------------------------------------------------------------
/src/cavalier_contours.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2025 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | import build
4 | from extension_helper import ExtensionHelper
5 |
6 | hook = ExtensionHelper('cavalier_contours', globals())
7 | hook.SkipConfigure()
8 | hook.InstallWhenIncluded(r'cavc/.+\.hpp')
9 | hook.AddCompileArg('-I' + str(hook.checkout_dir / 'include'))
10 |
--------------------------------------------------------------------------------
/src/channel_test.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include "channel.hh"
4 |
5 | #include
6 |
7 | #include
8 | #include
9 |
10 | using namespace automat;
11 |
12 | TEST(ChannelTest, SendForce) {
13 | channel c;
14 | c.send_force(std::make_unique(1));
15 | EXPECT_EQ(*c.recv(), 1);
16 | }
17 |
18 | TEST(ChannelTest, ManySenders) {
19 | channel c;
20 | for (int i = 0; i < 100; ++i) {
21 | std::thread([&c, i] { c.send(std::make_unique(i)); }).detach();
22 | }
23 | std::vector received;
24 | while (received.size() < 100) {
25 | received.push_back(*c.recv());
26 | }
27 | std::sort(received.begin(), received.end());
28 | for (int i = 0; i < 100; ++i) {
29 | EXPECT_EQ(received[i], i);
30 | }
31 | }
32 |
33 | TEST(ChannelTest, RecvBeforeSend) {
34 | channel c;
35 | std::thread([&c] {
36 | std::this_thread::sleep_for(std::chrono::milliseconds(100));
37 | c.send(std::make_unique(1));
38 | }).detach();
39 | EXPECT_EQ(*c.recv(), 1);
40 | }
41 |
--------------------------------------------------------------------------------
/src/complex_test.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include
4 |
5 | #include "base.hh"
6 | #include "library.hh"
7 | #include "test_base.hh"
8 |
9 | using namespace automat;
10 |
11 | struct ComplexTest : TestBase {
12 | Location& label = machine.Create();
13 | Location& complex = machine.Create();
14 | Location& field = machine.Create();
15 |
16 | ComplexTest() {
17 | label.SetText("X");
18 | field.ConnectTo(label, "label");
19 | field.ConnectTo(complex, "complex");
20 | field.Put(Create());
21 | }
22 | };
23 |
24 | TEST_F(ComplexTest, FollowField) {
25 | ASSERT_EQ(complex.As()->objects.size(), 1);
26 | EXPECT_EQ(complex.As()->objects.begin()->second.get(), field.Follow());
27 | }
28 |
29 | TEST_F(ComplexTest, TakeField) {
30 | ASSERT_EQ(complex.As()->objects.size(), 1);
31 |
32 | auto taken = field.Take();
33 | EXPECT_NE(taken.get(), nullptr);
34 | EXPECT_EQ(complex.As()->objects.size(), 0);
35 | }
36 |
37 | TEST_F(ComplexTest, CloneWithField) {
38 | field.Follow()->SetText(field, "Hello, world!");
39 |
40 | Location& clone = machine.Create(*complex.object, "Clone");
41 | EXPECT_NE(&complex, &clone);
42 | auto& [clone_label, clone_member] = *clone.As()->objects.begin();
43 | EXPECT_NE(field.Follow(), clone_member.get());
44 | EXPECT_EQ(clone_label, "X");
45 | EXPECT_EQ(clone_member->GetText(), "Hello, world!");
46 | }
47 |
--------------------------------------------------------------------------------
/src/connection.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include "connection.hh"
4 |
5 | #include "gui_connection_widget.hh"
6 | #include "location.hh"
7 | #include "root_widget.hh"
8 |
9 | using namespace automat::gui;
10 |
11 | namespace automat {
12 | Connection::~Connection() {
13 | auto [begin, end] = from.outgoing.equal_range(this);
14 | for (auto it = begin; it != end; ++it) {
15 | if (*it == this) {
16 | from.outgoing.erase(it);
17 | break;
18 | }
19 | }
20 | auto [begin2, end2] = to.incoming.equal_range(this);
21 | for (auto it = begin2; it != end2; ++it) {
22 | if (*it == this) {
23 | to.incoming.erase(it);
24 | break;
25 | }
26 | }
27 | if (root_widget) {
28 | for (int i = 0; i < root_widget->connection_widgets.size(); ++i) {
29 | auto& widget = *root_widget->connection_widgets[i];
30 | if (&widget.from == &from && &widget.arg == &argument) {
31 | widget.WakeAnimation();
32 | }
33 | }
34 | }
35 | if (from.object) {
36 | from.object->ConnectionRemoved(from, *this);
37 | }
38 | }
39 |
40 | Connection::Connection(Argument& arg, Location& from, Location& to,
41 | PointerBehavior pointer_behavior)
42 | : argument(arg), from(from), to(to), pointer_behavior(pointer_behavior) {}
43 | } // namespace automat
--------------------------------------------------------------------------------
/src/connection.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 | #include
7 |
8 | namespace automat {
9 |
10 | struct Location;
11 | struct Argument;
12 |
13 | struct Connection {
14 | enum PointerBehavior { kFollowPointers, kTerminateHere };
15 | Argument& argument;
16 | Location &from, &to;
17 | PointerBehavior pointer_behavior;
18 | Connection(Argument&, Location& from, Location& to, PointerBehavior);
19 | ~Connection();
20 | };
21 |
22 | struct ConnectionHasher {
23 | using is_transparent = std::true_type;
24 | size_t operator()(const Connection* c) const {
25 | return std::hash{}(&c->argument);
26 | }
27 | size_t operator()(const Argument* a) const { return std::hash{}(a); }
28 | };
29 |
30 | struct ConnectionEqual {
31 | using is_transparent = std::true_type;
32 | bool operator()(const Connection* a, const Connection* b) const {
33 | return &a->argument == &b->argument;
34 | }
35 | bool operator()(const Connection* a, const Argument* b) const { return &a->argument == b; }
36 | bool operator()(const Argument* a, const Connection* b) const { return a == &b->argument; }
37 | };
38 |
39 | } // namespace automat
--------------------------------------------------------------------------------
/src/control_flow.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | namespace automat {
6 |
7 | // Mechanism for controlling various search loops.
8 | enum class ControlFlow : char {
9 | VisitChildren = 0, // Continue the search including children of the current element.
10 | SkipChildren = 1, // Continue the search but don't visit the children of the current element.
11 | StopSearching = 2, // Stop the search immediately.
12 | };
13 |
14 | } // namespace automat
--------------------------------------------------------------------------------
/src/demo_static_vulkan_crash.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma maf main
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include
10 | #include
11 |
12 | int main() {
13 | void* library = dlopen("libvulkan.so.1", RTLD_NOW | RTLD_GLOBAL);
14 | printf("Loaded libvulkan.so.1\n");
15 | PFN_vkGetInstanceProcAddr ptr_vkGetInstanceProcAddr =
16 | reinterpret_cast(dlsym(library, "vkGetInstanceProcAddr"));
17 |
18 | PFN_vkCreateInstance fp_vkCreateInstance = reinterpret_cast(
19 | ptr_vkGetInstanceProcAddr(VK_NULL_HANDLE, "vkCreateInstance"));
20 |
21 | VkApplicationInfo applicationInfo = {
22 | .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
23 | .pApplicationName = "Hello world app",
24 | .applicationVersion = 0,
25 | .pEngineName = "awesomeengine",
26 | .engineVersion = 0,
27 | .apiVersion = VK_API_VERSION_1_0,
28 | };
29 |
30 | VkInstanceCreateInfo createInfo = {
31 | .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
32 | .flags = 0,
33 | .pApplicationInfo = &applicationInfo,
34 | .enabledLayerCount = 0,
35 | .ppEnabledLayerNames = nullptr,
36 | .enabledExtensionCount = 0,
37 | .ppEnabledExtensionNames = nullptr,
38 | };
39 |
40 | VkInstance instance;
41 | printf("Creating instance...\n");
42 | if (fp_vkCreateInstance(&createInfo, NULL, &instance) != VK_SUCCESS) {
43 | printf("Failed to create instance.\n");
44 | return EXIT_FAILURE;
45 | }
46 | printf("Instance created\n");
47 | PFN_vkDestroyInstance fp_vkDestroyInstance = reinterpret_cast(
48 | ptr_vkGetInstanceProcAddr(instance, "vkDestroyInstance"));
49 | fp_vkDestroyInstance(instance, NULL);
50 |
51 | printf("Demo failed to crash (yay!)\n");
52 |
53 | return EXIT_SUCCESS;
54 | }
55 |
--------------------------------------------------------------------------------
/src/dev_actions.py:
--------------------------------------------------------------------------------
1 | # SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | # SPDX-License-Identifier: MIT
3 | import make
4 | from pathlib import Path
5 | import subprocess
6 | import fs_utils
7 | import shutil
8 |
9 | def optimize_sfx():
10 | # go through every .wav file in assets and run
11 | # ffmpeg -i in.mov -map_metadata -1 -c:v copy -c:a copy -fflags +bitexact -flags:v +bitexact -flags:a +bitexact out.mov
12 | assets = fs_utils.project_root / 'assets'
13 | for wav_path in assets.glob('**/*.wav'):
14 | if wav_path.stem.endswith('_temp'):
15 | continue
16 | print(wav_path)
17 | temp_copy = wav_path.with_stem(wav_path.stem + '_temp')
18 | args = ['ffmpeg', '-i', str(wav_path), '-map_metadata', '-1', '-c:v', 'copy', '-c:a', 'copy', '-fflags', '+bitexact', '-flags:v', '+bitexact', '-flags:a', '+bitexact', str(temp_copy)]
19 | print('Running:', *args)
20 | subprocess.run(args, check=True)
21 | shutil.move(temp_copy, wav_path)
22 |
23 |
24 | def hook_recipe(recipe: make.Recipe):
25 | recipe.add_step(optimize_sfx, [], [])
26 |
--------------------------------------------------------------------------------
/src/drag_action.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 | #include
5 |
6 | #include
7 | #include
8 |
9 | #include "action.hh"
10 | #include "object.hh"
11 | #include "time.hh"
12 |
13 | namespace automat {
14 |
15 | struct Location;
16 |
17 | namespace gui {
18 |
19 | // Interface for widgets that can receive locations being dropped on them.
20 | struct DropTarget {
21 | virtual bool CanDrop(Location&) const = 0;
22 | virtual void SnapPosition(Vec2& position, float& scale, Location&,
23 | Vec2* fixed_point = nullptr) = 0;
24 |
25 | // When a location is being dragged around, its still owned by its original Machine. Only when
26 | // this method is called, the location may be re-parented into the new drop target.
27 | // The drop target is responsible for re-parenting the location!
28 | virtual void DropLocation(Ptr&&) = 0;
29 | };
30 | } // namespace gui
31 |
32 | struct DragLocationAction;
33 |
34 | struct DragLocationWidget : gui::Widget {
35 | DragLocationAction& action;
36 | DragLocationWidget(DragLocationAction& action) : action(action) {}
37 | SkPath Shape() const override;
38 | void FillChildren(Vec>& children) override;
39 | Optional TextureBounds() const override { return std::nullopt; }
40 | };
41 |
42 | struct DragLocationAction : Action {
43 | Vec2 contact_point; // in the coordinate space of the dragged Object
44 | Vec2 last_position; // root machine coordinates
45 | Vec2 current_position; // root machine coordinates
46 | Vec2 last_snapped_position; // root machine coordinates
47 | time::SteadyPoint last_update;
48 | Vec> locations;
49 | Ptr widget;
50 |
51 | DragLocationAction(gui::Pointer&, Ptr&&, Vec2 contact_point);
52 | DragLocationAction(gui::Pointer&, Vec>&&, Vec2 contact_point);
53 | ~DragLocationAction() override;
54 |
55 | void Update() override;
56 | gui::Widget* Widget() override { return widget.get(); }
57 | };
58 |
59 | bool IsDragged(const Location& location);
60 |
61 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawable.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include "drawable.hh"
4 |
5 | namespace automat {
6 |
7 | TextDrawable::TextDrawable(StrView text, float letter_size, gui::Font& font)
8 | : text(text), letter_size(letter_size), font(font) {
9 | width = font.MeasureText(text);
10 | }
11 |
12 | void TextDrawable::onDraw(SkCanvas* canvas) {
13 | canvas->translate(-width / 2, -letter_size / 2);
14 | font.DrawText(*canvas, text, paint);
15 | }
16 |
17 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawable.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #include "font.hh"
10 | #include "str.hh"
11 |
12 | namespace automat {
13 |
14 | // A minimal alternative to SkDrawable, for internal use in Automat.
15 | // Can be used to represent arbitrary object that can be drawn on a canvas.
16 | struct Drawable {
17 | virtual ~Drawable() = default;
18 | virtual void onDraw(SkCanvas*) = 0;
19 | };
20 |
21 | // A base class for Drawables that may be drawn with arbitrary SkPaint.
22 | struct PaintDrawable : Drawable {
23 | SkPaint paint;
24 | };
25 |
26 | struct TextDrawable : PaintDrawable {
27 | Str text;
28 | float width;
29 | float letter_size;
30 | gui::Font& font;
31 | TextDrawable(StrView text, float letter_size, gui::Font& font);
32 |
33 | void onDraw(SkCanvas* canvas) override;
34 | };
35 |
36 | struct DrawableSkPath : PaintDrawable {
37 | SkPath path;
38 | DrawableSkPath(SkPath path) : path(std::move(path)) {}
39 | void onDraw(SkCanvas* c) override { c->drawPath(path, paint); }
40 | };
41 |
42 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawable_rtti.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include "drawable_rtti.hh"
4 |
5 | #pragma maf add compile argument "-fno-rtti"
6 |
7 | namespace automat {
8 |
9 | struct SkDrawableNoRTTI : SkDrawable {
10 | std::unique_ptr drawable;
11 | SkDrawableNoRTTI(std::unique_ptr drawable) : drawable(std::move(drawable)) {}
12 | SkRect onGetBounds() override { return drawable->onGetBounds(); }
13 | void onDraw(SkCanvas* c) override { drawable->onDraw(c); }
14 | const char* getTypeName() const override { return drawable->getTypeName(); }
15 | void flatten(SkWriteBuffer& buffer) const override { drawable->flatten(buffer); }
16 | };
17 |
18 | SkDrawableRTTI& SkDrawableRTTI::Unwrap(SkDrawable& sk) {
19 | return *static_cast(sk).drawable;
20 | }
21 |
22 | sk_sp SkDrawableRTTI::Wrap(std::unique_ptr drawable) {
23 | return sk_sp(new SkDrawableNoRTTI(std::move(drawable)));
24 | }
25 |
26 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawable_rtti.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | namespace automat {
10 |
11 | struct SkDrawableRTTI;
12 |
13 | template
14 | concept SkDrawableRTTI_Subclass = std::derived_from;
15 |
16 | // For efficiency and Objective-C compatibility, Skia avoids C++ RTTI. Because of that it's not
17 | // possible to derive from Skia base classes in Automat. This class provides a workaround for that.
18 | // It can be used as a base class to provide an SkDrawable-compatible interface which then can be
19 | // wrapped in a custom SkDrawable adapter compiled with `-fno-rtti`.
20 | struct SkDrawableRTTI {
21 | SkDrawableRTTI() = default;
22 | virtual ~SkDrawableRTTI() = default;
23 |
24 | virtual SkRect onGetBounds() = 0;
25 | virtual void onDraw(SkCanvas*) = 0;
26 | virtual const char* getTypeName() const = 0;
27 | virtual void flatten(SkWriteBuffer&) const = 0;
28 |
29 | // Create an instance of T (derived from SkDrawableRTTI), wrap it in a sk_sp and
30 | // return it. Optionally store a pointer to the typed instance in typed_ptr. Once
31 | // sk_sp is destroyed, the *typed_ptr becomes invalid.
32 | template
33 | static sk_sp Make(T** typed_ptr = nullptr, Args&&... args) {
34 | T* ptr = new T(std::forward(args)...);
35 | if (typed_ptr) {
36 | *typed_ptr = ptr;
37 | }
38 | return Wrap(std::unique_ptr(ptr));
39 | }
40 |
41 | static SkDrawableRTTI& Unwrap(SkDrawable&);
42 |
43 | private:
44 | static sk_sp Wrap(std::unique_ptr drawable);
45 | };
46 |
47 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawing.cc:
--------------------------------------------------------------------------------
1 | #include "drawing.hh"
2 |
3 | #include
4 |
5 | #include "sincos.hh"
6 |
7 | namespace automat {
8 |
9 | void SetRRectShader(SkPaint& paint, const RRect& rrect, SkColor top, SkColor middle,
10 | SkColor bottom) {
11 | // Get the center point of the rounded rectangle
12 | SkPoint center = rrect.Center();
13 |
14 | // Define color stops for a sweep gradient
15 | // We'll use strategic positions to create the transitions between colors
16 | constexpr int count = 8;
17 | SkColor colors[count] = {
18 | middle, // right top
19 | top, // top right
20 | top, // top left
21 | middle, // left top
22 | middle, // left bottom
23 | bottom, // bottom left
24 | bottom, // bottom right
25 | middle, // right bottom
26 | };
27 |
28 | auto Angle = [](Vec2 v) -> float { return SinCos::FromVec2(v).ToRadiansPositive() / M_PI / 2; };
29 |
30 | // Position stops at strategic angles (in 0-1 range where 1.0 = 360°, 0 = stright right)
31 | float positions[count] = {
32 | Angle(rrect.LineEndRightUpper()), Angle(rrect.LineEndUpperRight()),
33 | Angle(rrect.LineEndUpperLeft()), Angle(rrect.LineEndLeftUpper()),
34 | Angle(rrect.LineEndLeftLower()), Angle(rrect.LineEndLowerLeft()),
35 | Angle(rrect.LineEndLowerRight()), Angle(rrect.LineEndRightLower()),
36 | };
37 |
38 | paint.setShader(SkGradientShader::MakeSweep(center.x(), center.y(), colors, positions, count));
39 | }
40 |
41 | } // namespace automat
--------------------------------------------------------------------------------
/src/drawing.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2025 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 |
7 | #include "math.hh"
8 |
9 | // Utilities for drawing things on the screen.
10 |
11 | namespace automat {
12 |
13 | // Configure the paint to draw a smooth gradient that shades the given rrect from top to bottom.
14 | //
15 | // This should be used for borders - the inner color of the SkPaint will draw artifacts.
16 | //
17 | // TODO: switch this from a simple conic gradient into a proper rrect-based shader.
18 | void SetRRectShader(SkPaint& paint, const RRect& rrect, SkColor top, SkColor middle,
19 | SkColor bottom);
20 |
21 | } // namespace automat
--------------------------------------------------------------------------------
/src/embedded.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include "../build/generated/embedded.hh" // IWYU pragma: export
6 |
--------------------------------------------------------------------------------
/src/error.cc:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #include "error.hh"
4 |
5 | #include "object.hh"
6 |
7 | namespace automat {
8 |
9 | Error::~Error() {}
10 |
11 | Error::Error(std::string_view text, std::source_location source_location)
12 | : text(text), source(nullptr), saved_object(nullptr), source_location(source_location) {}
13 | } // namespace automat
--------------------------------------------------------------------------------
/src/error.hh:
--------------------------------------------------------------------------------
1 | // SPDX-FileCopyrightText: Copyright 2024 Automat Authors
2 | // SPDX-License-Identifier: MIT
3 | #pragma once
4 |
5 | #include
6 | #include
7 |
8 | #include "ptr.hh"
9 |
10 | namespace automat {
11 |
12 | struct Location;
13 | struct Object;
14 |
15 | /*
16 | The goal of Errors is to explain to the user what went wrong and help with
17 | recovery.
18 |
19 | Errors can be placed in Locations (alongside Objects). Each location can hold up
20 | to one Error.
21 |
22 | While present, Errors pause the execution at their locations. Each object is
23 | responsible for checking the error at its location and taking it into account
24 | when executing itself.
25 |
26 | Errors keep track of their source (object? location?) which is usually the same
27 | as their location. Some objects can trigger errors at remote locations to pause
28 | them.
29 |
30 | Errors can be cleaned by the user or by their source. The source of the error
31 | should clean it automatically - but sometimes it can be executed explicitly to
32 | recheck conditions & clean the error. Errors caused by failing preconditions
33 | clear themselves automatically when an object is executed.
34 |
35 | Errors can also save objects that would otherwise be deleted. The objects are
36 | held in the Error instance and can be accessed by the user.
37 |
38 | In the UI the errors are visualized as spiders sitting on the error locations.
39 | Source of the error is indicated by a spider web. Saved objects are cocoons.
40 |
41 | When an error is added to an object it causes a notification to be sent to all
42 | `error_observers` of the object. The observers may fix the error or notify the
43 | user somehow. The parent Machine is an implicit error observer and propagates
44 | the error upwards. Top-level Machines print their errors to the console.
45 | */
46 | struct Error {
47 | std::string text;
48 | Location* source;
49 | Ptr