├── .github └── workflows │ └── build.yml ├── .gitignore ├── CNAME ├── CONTRIBUTING.md ├── README.md ├── book.toml ├── context.json ├── src ├── README.md ├── SUMMARY.md ├── build_tools │ ├── README.md │ ├── hash.md │ ├── libs_json_reference.md │ ├── premake.md │ ├── tmbuild.md │ └── tmbuild_package_reference.md ├── collaboration.md ├── contributing.md ├── creation_graphs │ ├── concept.md │ ├── intro_unity.md │ ├── intro_unreal.md │ ├── node_types.md │ └── shader_system.md ├── editing_workflows │ ├── README.md │ ├── animation │ │ ├── README.md │ │ ├── animation-compression.md │ │ └── animation-state-machine.md │ ├── asset_pipeline.md │ ├── entities.md │ ├── import_assets.md │ ├── import_projects.md │ ├── physics.md │ ├── prototype_workflow │ │ ├── README.md │ │ ├── how_to_create_prototypes.md │ │ └── how_to_instantiate_prototypes.md │ ├── publish.md │ ├── sculpting.md │ ├── shaders_materials.md │ ├── simulation.md │ ├── sound.md │ └── visual-scripting.md ├── extending_the_machinery │ ├── README.md │ ├── application_hooks.md │ ├── hot-reloading.md │ ├── plugin-assets.md │ ├── sample_plugin.md │ ├── the_plugin_system.md │ ├── write-a-plugin.md │ └── write-a-tab.md ├── faq.md ├── gameplay_coding │ ├── README.md │ ├── ecs │ │ ├── README.md │ │ ├── filtering_entities.md │ │ ├── how_entites_can_interact.md │ │ ├── how_to_define_a_engine_system.md │ │ ├── how_to_design_system_or_engine.md │ │ ├── how_to_register_a_system_or_engine.md │ │ ├── simulation_lifecycle.md │ │ ├── tagging_entities.md │ │ ├── what_are_components.md │ │ └── write_a_custom_component.md │ ├── gameplay_entry_comparison.md │ ├── simulation_entry.md │ └── visual_scripting │ │ ├── README.md │ │ ├── debugger.md │ │ ├── extend_the_entity_graph.md │ │ ├── provide_custom_data_type_to_the_entity_graph.md │ │ └── subgraphs.md ├── getting_started │ ├── README.md │ ├── first_gameplay_project.md │ ├── introduction_to_c │ │ ├── README.md │ │ ├── concurrency.md │ │ ├── hashmaps_and_set.md │ │ ├── list_arrays_vector.md │ │ ├── memory_management.md │ │ ├── other.md │ │ └── strings.md │ ├── logging_in.md │ ├── migration_from_godot.md │ ├── migration_from_unity.md │ ├── migration_from_unreal.md │ ├── new_project.md │ ├── project_setup.md │ ├── sample-projects.md │ ├── version_control.md │ └── what_is_in_the_package.md ├── glossary.md ├── graphics │ ├── README.md │ ├── camera.md │ ├── camera │ │ ├── README.md │ │ └── physical_light_and_camera.md │ ├── default_render_pipeline.md │ ├── lighting │ │ ├── README.md │ │ └── ambient_occlusion.md │ ├── mesh_materials.md │ ├── physical_light_and_camera.md │ ├── post_processing │ │ ├── README.md │ │ ├── aa.md │ │ ├── bloom.md │ │ ├── color_grading.md │ │ └── exposure.md │ ├── shaders.md │ ├── the_machinery_shading_language.md │ └── tmsl_vs.md ├── licenses.md ├── qa_pipeline │ ├── README.md │ ├── how_to_write_integration_tests.md │ ├── how_to_write_unit_tests.md │ ├── logging.md │ ├── memory.md │ ├── profiler.md │ └── statistics.md ├── the_editor │ ├── README.md │ ├── asset_browser.md │ ├── customizations.md │ ├── entity_tree_tab.md │ ├── preview_tab.md │ ├── properties_tab.md │ ├── scene_tab.md │ ├── simulate_tab.md │ └── tabs.md ├── the_truth │ ├── README.md │ ├── access_values.md │ ├── aspects.md │ ├── common_types.md │ ├── create_an_object.md │ ├── custom_truth_type.md │ └── modify_an_object.md ├── troubleshooting.md ├── tutorials │ ├── README.md │ ├── creation_graph │ │ ├── README.md │ │ ├── custom_cpu_nodes.md │ │ ├── custom_geometry_node.md │ │ ├── custom_gpu_nodes.md │ │ ├── from_code.md │ │ ├── introduction_walkthrough │ │ │ ├── README.md │ │ │ ├── creation_graph_prototype.md │ │ │ ├── custom_import_settings.md │ │ │ └── texture_compression.md │ │ └── raymarch_output_node.md │ ├── network │ │ ├── README.md │ │ └── animation_sample │ │ │ ├── basic_graph_variables.md │ │ │ ├── entity_control.md │ │ │ ├── multiple_network_instances.md │ │ │ ├── network_assets.md │ │ │ ├── smooth_animation.md │ │ │ ├── spawning_entities.md │ │ │ └── support_multiple_players.md │ ├── physics │ │ ├── README.md │ │ ├── arkanoid.md │ │ ├── contacts.md │ │ ├── kinematic.md │ │ ├── stack.md │ │ └── triggers.md │ ├── the_truth │ │ ├── README.md │ │ ├── custom_asset │ │ │ ├── README.md │ │ │ ├── part1.md │ │ │ ├── part2.md │ │ │ └── part3.md │ │ ├── drag_and_drop.md │ │ └── open_asset.md │ └── ui │ │ ├── README.md │ │ ├── build_custom_ui_controls │ │ ├── README.md │ │ └── part1.md │ │ ├── custom_layouts.md │ │ └── toolbars-overlays.md ├── what_is_the_machinery.md └── writing_an_executable.md ├── terms.json └── theme └── head.hbs /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build github page 2 | on: 3 | workflow_dispatch: 4 | branches: 5 | - main 6 | jobs: 7 | deploy: 8 | runs-on: ubuntu-latest 9 | env: 10 | TM_BOOK_CODE_SNIPPETS: ${{github.workspace}}/samples/examples 11 | TM_SDK_DIR: ${{github.workspace}}/sdk_dir/headers 12 | steps: 13 | - name: Checkout website 14 | uses: actions/checkout@v2 15 | with: 16 | path: ./ 17 | - name: Checkout themachinery-book-code-snippets repo 18 | uses: actions/checkout@v2 19 | with: 20 | path: samples 21 | repository: OurMachinery/themachinery-book-code-snippets 22 | token: ${{ secrets.SAMPLE_REPO_TOKEN }} 23 | - name: download SDK 24 | run: | 25 | sudo apt install -y unzip wget 26 | wget https://ourmachinery.com/releases/2022.2/the-machinery-2022.2-linux.zip 27 | mkdir sdk_dir 28 | unzip the-machinery-2022.2-linux.zip -d sdk_dir 29 | - name: Setup tmbook 30 | run: | 31 | wget https://github.com/simon-ourmachinery/tmbook/releases/download/latest/tmbook 32 | chmod +x tmbook 33 | - name: Build book 34 | run: | 35 | sed -i "s/#//" book.toml 36 | ./tmbook build 37 | cp CNAME book/CNAME 38 | - name: Deploy 39 | uses: peaceiris/actions-gh-pages@v3 40 | with: 41 | github_token: ${{ secrets.GITHUB_TOKEN }} 42 | publish_dir: ./book 43 | - name: Report 44 | uses: 8398a7/action-slack@v3 45 | with: 46 | status: ${{ job.status }} 47 | fields: repo,message,commit,author,action,eventName,ref,workflow,job 48 | env: 49 | SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} 50 | if: always() 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | mdbook-bin 3 | *.exe 4 | 5 | code_snippets/ 6 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | books.ourmachinery.com -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | If you want to make a contribution to this repository (other than a small spelling or formatting fix), please first create an *Issue* or a *Discussion* thread, discussing the addition you want to make. Otherwise, there is a chance your submission will be rejected if we decide it does not fit into the structure of this document. 4 | 5 | We reserve the right to edit and reject contributions. 6 | 7 | ## Contributor's License Agreement 8 | 9 | By submitting pull requests to this repository you represent that: 10 | 11 | - You are the copyright owner of the text you are submitting. 12 | - You grant to Our Machinery and to recipients of our software and source code a perpetual, worldwide non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute your contributions and derivative work. 13 | - You are legally entitled to grant the above license. If your employer, if any, has rights to intellectual property that you create, you represent that you have received permissions to make this contribution on behalf of your employer. 14 | 15 | If you do not agree with any of these representations, do not submit pull requests to the repository. 16 | 17 | ## Code of Conduct 18 | 19 | * Please be nice and respectful, don't be rude. 20 | 21 | - Any kind of hate speech leads to being banned. 22 | - Think before you type, especially when you feel that a discussion is becoming heated. 23 | - Listen to Our Machinery Team members. 24 | - Keep discussions in the correct forums. 25 | 26 | -------------------------------------------------------------------------------- /book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["The OurMachinery Team"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "The Machinery Book" 7 | 8 | [output.html] 9 | git-repository-url = "https://github.com/OurMachinery/themachinery-books" 10 | 11 | [output.html.fold] 12 | enable = true 13 | 14 | [preprocessor.toc] 15 | command = "./tmbook toc" 16 | renderer = ["html"] 17 | marker = "* {:toc}" 18 | 19 | [preprocessor.links] 20 | 21 | 22 | [preprocessor.path_replacement] 23 | renderer = ["html"] 24 | books = ["the_machinery_book"] 25 | command = "./tmbook path_replacement" 26 | 27 | 28 | [preprocessor.auto_doc] 29 | renderer = ["html"] 30 | books = ["the_machinery_book"] 31 | command = "./tmbook auto_doc" 32 | 33 | [preprocessor.auto_include] 34 | renderer = ["html"] 35 | books = ["the_machinery_book"] 36 | command = "./tmbook auto_include" 37 | 38 | -------------------------------------------------------------------------------- /context.json: -------------------------------------------------------------------------------- 1 | { 2 | "base_url": "https://ourmachinery.github.io/themachinery-books/", 3 | "docs": "https://ourmachinery.com/apidoc/" 4 | } -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | Hi, 2 | 3 | Thanks for using *The Machinery*. We're excited to share with the world what we have cooked up and happy to have you among the people that are trying out the engine. This book is here to give you a little bit of background and information about what you're looking at. 4 | 5 | Besides this book we have several other resources which might be good to checkout: 6 | 7 | - [Our API Documentation]({{docs}}apidoc.html) 8 | - [Our Blog](https://ourmachinery.com/post/) 9 | - [Our Podcast](https://anchor.fm/ourmachinery) 10 | - [Our Discord](https://discord.gg/SHHSZaH) 11 | - [Our Github Discussion Board](https://github.com/OurMachinery/themachinery-public/discussions) 12 | - [Tutorials and Workflow Book]({{base_url}}) 13 | 14 | Also feel free to checkout our internal 15 | 16 | - [Programming Guidebook](https://ourmachinery.com/apidoc/doc/guidebook.md.html) 17 | 18 | > The purpose of this [Programming Guidebook](https://ourmachinery.com/apidoc/doc/guidebook.md.html) is to lay down principles and guidelines for how to write code and work together at Our Machinery. 19 | 20 | Enjoy! 21 | 22 | *The Machinery Team* 23 | 24 | > ⚠ **This book is currently a work in progress:** Feel free to contribute to it via [OurMachinery/themachinery-books](https://github.com/OurMachinery/themachinery-books). Either create a Pull Request, or submit an issue. 25 | > 26 | > ℹ️ **Dropbox usage:** This book makes use of Dropbox for our image storage. Therefore if you are using a agressive ad-blocker some images might not load. 27 | 28 | ## Introduction to the Engine 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/build_tools/README.md: -------------------------------------------------------------------------------- 1 | # Helper Tools 2 | 3 | The Machinery comes with a few tools to make your daily life easier. There are tools for: 4 | 5 | - Generating Static Hash Values: `hash` 6 | - Generate Graph Nodes for you:`generate-graph-nodes` 7 | - To generate the solution files of The Engine or your plugin: `tmbuild` 8 | - Execute your unit tests: `unit-test` 9 | - Generate your Localization tables: `localize` 10 | - Free your Plugins from unneeded includes: `trim-includes.exe` 11 | 12 | -------------------------------------------------------------------------------- /src/build_tools/hash.md: -------------------------------------------------------------------------------- 1 | # How to use hash.exe 2 | 3 | This walkthrough introduces you to hash.exe and shows you how to use it with The Machinery. 4 | 5 | You will learn about: 6 | 7 | - How to use `hash.exe` and `TM_STATIC_HASH` 8 | 9 | ## How to use hash.exe and TM_STATIC_HASH 10 | 11 | While working with The Machinery, you will have surely noticed that its systems often expect a hashed version of a string as input. In this document, we will be dealing with static hashes defined with [TM_STATIC_HASH]({{docs}}foundation/api_types.h.html#tm_static_hash()) to identify, for example, a type in our data model, [The Truth]({{base_url}}the_truth/index.html). If you are searching documentation on runtime hashes, you’ll want to check out the [murmurhash64a.inl]({{docs}}foundation/murmurhash64a.inl.html#murmurhash64a.inl) files. 12 | 13 | In this document, we will be using hash.exe to generate new hash values or update the changed ones. The hash.exe utility checks the entire source code and makes sure that wherever you use `TM_STATIC_HASH`, the numeric value v matches the actual hash of the string s (if not, the code is updated). If you do not run the executable before you build, you will have compile errors. 14 | 15 | > **Note**: `tmbuild` has the option to run hash.exe before it builds. `tmbuild --gen-hash`. 16 | 17 | Let us look at where this tool is useful and is being used a lot: In [The Truth]({{base_url}}the_truth/index.html). 18 | 19 | For example, When defining Truth Objects or Types, we are using this tool to hash the name of the type statically 20 | 21 | ```c 22 | //... 23 | 24 | #define TM_TT_TYPE__ASSET "tm_asset" 25 | 26 | #define TM_TT_TYPE_HASH__ASSET TM_STATIC_HASH("tm_asset", 0xca71127abbb72960ULL) 27 | 28 | enum { 29 | 30 | TM_TT_PROP__ASSET__NAME = 0, // string 31 | 32 | TM_TT_PROP__ASSET__DIRECTORY, // reference(ASSET_DIRECTORY) 33 | 34 | TM_TT_PROP__ASSET__UUID_TAGS, // subobject_set(UINT64_T) storing the UUID of the associated tag. 35 | 36 | TM_TT_PROP__ASSET__OBJECT, // subobject(*) 37 | 38 | }; 39 | 40 | //... 41 | ``` 42 | 43 | In the above example we have the definition of the Truth Type tm_asset. The `#define TM_TT_TYPE_HASH__ASSET TM_STATIC_HASH("tm_asset", 0xca71127abbb72960ULL)` was generated by the hash utility. Before the tool ran the code looked similar to this: `#define TM_TT_TYPE_HASH__ASSET TM_STATIC_HASH("tm_asset")` 44 | 45 | For example later on we can use it to create an object of this type. If we do not have the corresponding type id `tm_tt_type_t` we need to ask The Truth: 46 | 47 | ```c 48 | tm_the_truth_api->object_type_from_name_hash(tt, TM_TT_TYPE_HASH__ASSET); 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /src/build_tools/libs_json_reference.md: -------------------------------------------------------------------------------- 1 | # tmbuild libs.json Reference 2 | 3 | The `tmbuild` expetcs a `libs.json` file that descibes what kind of binary dependencies your project has. This file needs to adhere to the scheme described here. 4 | 5 | **Example:** 6 | 7 | ``` 8 | { 9 | "name of the libs": { 10 | "build-platforms": [ 11 | "what platform", 12 | ], 13 | "lib": "name of the lib zip file", 14 | "role": "role" 15 | }, 16 | } 17 | ``` 18 | 19 | | Setting Parameter | Type | Required | Description | 20 | | ------------------ | ---------------- | -------- | ------------------------------------------------------------ | 21 | | Name of the lib | Json Object | Yes | Each Dependency needs a object with its name. | 22 | | `build-platforms` | Array of Strings | No | Array of build platforms this lib can be used in. | 23 | | `target-platforms` | Array of Strings | No | Array of target platforms this lib supports. Target platforms are platforms that can be used to cross compile your application with `tmbuild --platform [platform]` | 24 | | `lib` | String | Yes | This is the name of the libs' zip file. This will be fetched from `tmbuild` form the dependency repository. | 25 | | `role` | String | Yes | Describes the role of the dependency. | 26 | | `repository` | String | No | In case you want to use a custom repository for your own depdencies you can use this to provide a url. This url can be HTTP or HTTPS. The data should be stored there as zips. | 27 | | `fingerprint` | String | No | Allows you to provide your own HTTPS fingerprint. | -------------------------------------------------------------------------------- /src/contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We are welcoming all contributions to the [Engine](https://github.com/OurMachinery/themachinery) or the [Books](https://github.com/OurMachinery/themachinery-books). Any kind of contributions must follow the following requirements. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | ## Contributing to Books 9 | 10 | If you want to make a contribution to [this repository](https://github.com/OurMachinery/themachinery-books) (other than a small spelling or formatting fix), please first create an *Issue* or a *Discussion* thread, discussing the addition you want to make. Otherwise, there is a chance your submission will be rejected if we decide it does not fit into the structure of this document. 11 | 12 | We reserve the right to edit and reject contributions. 13 | 14 | 15 | 16 | ### Contributor's License Agreement 17 | 18 | By submitting pull requests to this repository you represent that: 19 | 20 | - You are the copyright owner of the text you are submitting. 21 | - You grant to Our Machinery and to recipients of our software and source code a perpetual, worldwide non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute your contributions and derivative work. 22 | - You are legally entitled to grant the above license. If your employer, if any, has rights to intellectual property that you create, you represent that you have received permissions to make this contribution on behalf of your employer. 23 | 24 | If you do not agree with any of these representations, do not submit pull requests to the repository. 25 | 26 | 27 | 28 | ## Contribution to The Machinery 29 | 30 | If you want to make a contribution to the [main repo](https://github.com/OurMachinery/themachinery), please first create an [issue tracker](https://github.com/OurMachinery/themachinery-public/issues) or [*Issue*](https://github.com/OurMachinery/themachinery/issues),or a [*Discussion*](https://github.com/OurMachinery/themachinery-public/discussions) thread, discussing the addition you want to make. Besides you should read [Code Guide Book](https://ourmachinery.com/apidoc/doc/guidebook.md.html) before you start your Pull Request. Otherwise, there is a chance your submission will be rejected your Pull Request. 31 | 32 | We reserve the right to edit and reject contributions. 33 | 34 | 35 | 36 | ### Contributor's License Agreement 37 | 38 | By submitting pull requests to this repository you represent that: 39 | 40 | - You are the copyright owner of the code you are submitting. 41 | - You grant to *Our Machinery* and to recipients of our software and source code a perpetual, worldwide non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense and distribute your contributions and derivative work. 42 | - You are legally entitled to grant the above license. If your employer, if any, has rights to intellectual property that you create, you represent that you have received permissions to make this contribution on behalf of your employer. 43 | 44 | If you do not agree with any of these representations, do not submit pull requests to the repository. 45 | 46 | 47 | 48 | ## Code of Conduct 49 | 50 | - Please be nice and respectful, don't be rude. 51 | 52 | - Any kind of hate speech leads to being banned. 53 | - Think before you type, especially when you feel that a discussion is becoming heated. 54 | - Listen to Our Machinery Team members. 55 | - Keep discussions in the correct forums. -------------------------------------------------------------------------------- /src/creation_graphs/concept.md: -------------------------------------------------------------------------------- 1 | # Creation Graphs 2 | 3 | The Creation Graph is used to create asset pipelines and also define GPU-related things such as materials and shaders. In essence it lets you set up a graph that takes some inputs and processes them using nodes that may run on either the CPU or GPU, the graph can then output things such as shader instances, images or draw calls. The big power of the Creation Graph is that it lets you reason about data that lives in the borderland between GPU and CPU, but being able to do so within one single graph. 4 | 5 | Creations Graphs live separately from Entity Graphs. You often find Creation Graphs living under Render Components (for issuing draw calls), or within `.creation_graph` assets, where they are used to define materials and images. As an example, a Creation Graph that outputs an image probably takes an image that lives on the disk as input, uploads it to the GPU and then has the graph output a GPU image. However, the user is then free to add nodes in-between these steps, for example node for compression or mipmap generation. Compared to other game engines, things that often end up in the properties panel of an import image, can here be done dynamically in a graph, depending on the needs of your project. 6 | 7 | Within the `core` folder that we ship with the engine you will find several creation graphs, many of these are used for defining defaul materials and also as defaults graph for use within our DCC asset import pipeline. 8 | 9 | ![Simple red material](https://www.dropbox.com/s/w5ty4r8tttntt0t/tm_guide_creation_graph_simple_material.png?raw=1) 10 | 11 | Image loading and material creation are just a few examples of what can be achieved with the creation graph. The table below shows when a creation graph is used compared to the tools one could use in Unity and Unreal. 12 | 13 | | Asset Type | Unity | Unreal | The Machinery | 14 | | -------------------- | -------------------- | ----------- | ------------------------------- | 15 | | Images | Texture | Texture | Creation Graph with Image Output node | 16 | | Materials | Shader | Material | Creation Graph with Shader Instance Output node | 17 | | Particles | Particle Effect | Cascade | Creation Graph with GPUSim nodes that emits particles | 18 | | Procedural materials | Procedural Materials | Material | Creation Graph with Image Output node with dynamic logic | 19 | | Meshes | Mesh | Static Mesh | DCC Asset referred to by Creation Graph within Render Component | 20 | 21 | The engine comes with a Creation Graphs sample, it contains examples of how to make materials and particle systems. 22 | 23 | Like the entity graph, the creation graph can executes nodes in sequence from an event. Some examples of this are the `Tick`, `Init`, and `Compile` events which are executed at known points or intervals. However, creation graphs commonly work using a a reverse flow where an output node is triggered and then all the nodes it depends on are run, in order to supply the output. Examples of these outputs are `Draw Call`, `Shader Instance`, `Image`, and `Physics Shape`. Note that these outputs are just blobs of data interpreted by the code that uses them. You can in other words add your own output nodes and types from code. 24 | 25 | -------------------------------------------------------------------------------- /src/creation_graphs/intro_unity.md: -------------------------------------------------------------------------------- 1 | # Creation Graphs for Unity Developers 2 | 3 | When a creation graph is used as a surface shader it most closely resembles to Unity's shader graph. This is what we will focus on first. 4 | 5 | ![Simple surface shader](https://www.dropbox.com/s/lg5dir5rxbz8c6l/tm_guide_creation_graph_unity.png?raw=1) 6 | 7 | In the example above the editor's layout was made to resemble Unity's shader graph view. When creating a material shader you need to have a `Shader Instance` output node. From here we can specify our shader by adding node to the left of the `Shader Instance` node. In this example the `Lit` node closely resembles Unity's `PBR Master` node. -------------------------------------------------------------------------------- /src/creation_graphs/intro_unreal.md: -------------------------------------------------------------------------------- 1 | # Creation Graphs for Unreal Engine developers 2 | 3 | Creation graphs are used for many different assets in The Machinery. When a creation graph is used for a shader it most closely relates to Unreal’s materials (any domain). This is what we will focus on first. 4 | 5 | ![Simple brick material](https://www.dropbox.com/s/nxy6jtq7f5drmin/tm_guide_creation_graph_unreal_material.png?raw=1) 6 | 7 | 8 | In the example above the editor closely resembles the material editor from Unreal, this is however not the default layout. You can see the creation graph in the center with its output being a `Shader Instance`. Adding this allows any consuming code to query the material from this creation graph and it will allow the preview tab to display your material. 9 | 10 | ![Simple rotating particle](https://www.dropbox.com/s/kpf05fwzl47d0ip/tm_guide_creation_graph_unreal_particle.png?raw=1) 11 | 12 | 13 | The previous example showed a surface or material shader. This example shows a creation graph that fully defines a simple particle. The `Shader Instance` (material) is now passed to a `Draw Call` node, with this combination we can now fully render the particle without the need of an explicit mesh. Instead we use the `Construct Quad` node for a procedural quad mesh. Note that we specify the `Instance Count` and `Num Vertices` (for a single quad that is 6). -------------------------------------------------------------------------------- /src/creation_graphs/node_types.md: -------------------------------------------------------------------------------- 1 | # Node types 2 | 3 | Nodes in the creation graph can be subdivided into four types, understanding the difference between these nodes is important when creating new nodes. The diagram below shows how each node can be categorized. 4 | 5 | ![](https://www.dropbox.com/s/h4uni5g7syk0zgn/tm_guide_creation_graph_node_types_graph.png?raw=1) 6 | 7 | 8 | GPU nodes are somewhat special as they will be compiled down into a single shader instead of being interpreted like the CPU part of the creation graph. Note that GPU nodes also have a different background color to distinguish them. GPU nodes will not connect to any CPU node unless their output is a `Shader Instance`, this is the point at which the GPU portion of the graph is compiled and passed to the CPU. 9 | 10 | The CPU portion of a creation graph is very similar to the entity graph in terms of layout with one exception. The creation graph often works by querying `output nodes` from the creation graph and working its way back from there. `event nodes` on the other hand allow you to follow the same flow as the entity graph, beginning from some event and continuing into other nodes. 11 | 12 | ![](https://www.dropbox.com/s/poi2rg73gttdixz/tm_guide_creation_graph_node_types_practical.png?raw=1) 13 | 14 | In the example above you can see a creation graph that uses the `Draw Call` and `Bounding Volume` output nodes. A Creation Graph with these kinds of nodes is commonly found living under the Render Component, since such a componen will automatically process any draw calls. The inputs to this graph are: a DCC mesh and a `Lit Shader Instance`, where the latter can be thought of as a shader or material. Note the `Variable` GPU node that is used to pass the color from the CPU side to the GPU side, this is the only way to connect CPU nodes to GPU nodes. 15 | Currently we support the following output nodes, note that multiple of these can be present in a single creation graph. 16 | 17 | | **Name** | **Information** | 18 | | ---------------------------------- | --------------------------------------------------------------- | 19 | | Image Output | Often used by Image assets and can be supplied to materials as textures etc. Allows preview of the Image. | 20 | | Bounding Volume | Used for culling. | 21 | | Draw Call | Generally used with the `Render Component`, allows preview. | 22 | | Shader Instance | Can be used as a material, allows preview. | 23 | | Physics Shape | Generally used with a `Physics Shape Component`. | 24 | | Ray Trace Instance | Used to generate acceleration structures and hit shaders. | 25 | | Entity Spawner - Output Transforms | Can be used to query transforms from the `Entity Spawner` node. | -------------------------------------------------------------------------------- /src/creation_graphs/shader_system.md: -------------------------------------------------------------------------------- 1 | # Shader system interaction 2 | 3 | A creation graph interacts with the shader system in three main ways: 4 | 5 | - Its GPU nodes are defined using `.tmsl` shaders. 6 | - GPU output nodes call special linker functions to evaluate the creation graph. 7 | - Shader instances in a creation graph are constructed using the shader system. 8 | 9 | The last point is a technical detail that doesn’t matter for anyone extending or using the creation graph so it won’t be covered in this guide. Additional information about the `creation_graph_node` shader block can be found in the [Shader System Reference]({{docs}}doc/shader_system_reference.md.html). 10 | 11 | Any GPU node that can be used in the creation graph has an associated `.tmsl` shader file. Most of these can be found here: `the_machinery/shaders/nodes/*.tmsl`. We also supply a [Visual Studio extension](https://marketplace.visualstudio.com/items?itemName=OurMachinery.tmShaderLang) for this file format which adds syntax highlighting, this extension will be used in this guide. 12 | 13 | ![](https://www.dropbox.com/s/4o13cq3rzvqm813/tm_guide_creation_graph_sin_node.png?raw=1) 14 | 15 | 16 | This is the shader code for the `Sin` node. It defines one input (`a`) and one output (`res`, which is the same type as `a`). This shader file will be constructed using the shader system into a single `.hlsl` function. For more information on how to create basic GPU nodes see [Creating custom GPU Nodes]({{base_url}}tutorials/creation_graph/custom_gpu_nodes.html). 17 | 18 | ![](https://www.dropbox.com/s/cs31mi8njs9gpno/tm_guide_creation_graph_linkage.png?raw=1) 19 | 20 | 21 | This is an example of the shader code needed in the creation graph output nodes. When a creation graph node outputs a `Shader Instance` and has any inputs; it should define these three functions in it’s shader code block so the graph can be evaluated. The `tm_graph_read` function passes all the stage input variables to the graph (like position, color, uv, etc.). The `tm_graph_evaluate` function does most of the work. It uses the `tm_graph_io_t` struct to evaluate the graph by calling the functions generated by the normal nodes. Finally the `tm_graph_write` function passes all the graph variable to the stage output. It is important to note that whilst the `tm_graph_evaluate` function is necessary for graph evaluation; the `tm_graph_read` and `tm_graph_write` are not, they are helper function. For more information on how to create GPU output nodes see [Creating custom GPU Nodes]({{base_url}}tutorials/creation_graph/custom_gpu_nodes.html). -------------------------------------------------------------------------------- /src/editing_workflows/README.md: -------------------------------------------------------------------------------- 1 | # Basic editing workflow 2 | 3 | The basic scene editing workflow in *The Machinery* looks something like this: 4 | 5 | 1. Import some asset files into the Asset Browser using **File > Import…** If you don't have any 6 | models to work with you can find free ones at [Sketchfab](https://sketchfab.com) for example. 7 | 8 | 2. Organize the files by right-clicking the Asset Browser and choosing **New > New Folder** and by 9 | dragging and dropping. 10 | 11 | 3. Any imported model, for example `fbx` or `gltf`, will appear as a `dcc_asset`. 12 | 13 | 4. Rig an entity from the `dcc_asset` by selecting it and clicking *Import Assets* in the property 14 | panel. This also imports the materials and images inside the `dcc_asset`. 15 | 16 | 5. Double click the imported entity to open it for editing. 17 | 18 | 6. Add components for physics, animation, scripting, etc to the entity. 19 | 20 | 7. Open a scene entity that you want to place your imported entity inside. A new project has a scene 21 | entity called `world.entity` that you can use. Or you can create your own scene entity by right 22 | clicking in the Asset Browser and choosing **New > New Entity**. 23 | 24 | 8. Drag your asset entities into the scene entity to position them in the scene. 25 | 26 | 9. Use the Move, Rotate, and Scale tools in the Scene tab to arrange the sub-entities. 27 | 28 | 10. Holding down *shift* while using the move tools creates object clones. 29 | 30 | 11. Select entities or components in the Entity Tree and Scene tabs to modify their properties using the 31 | Properties Tab. 32 | 33 | 12. Drag and drop in the Entity Tree Tab to re-link entities. 34 | 35 | 13. Each tool (Move, Rotate and Scale) has tool-specific settings, such as snapping and pivot point, in 36 | the upper-left corner of the scene tab. 37 | 38 | 14. Use **Scene > Frame Selection** and **Scene > Frame Scene** to focus the 39 | camera on a specific selected entity, or the entire scene. Or just use the _F key_. 40 | 41 | 15. When you are done, use **File > Save Project…** to save the scene for future 42 | work. 43 | 44 | > **Known issues:** When you drag a tab out of the current window to create a new one, you don’t 45 | > get any visual feedback until the new window is created. 46 | -------------------------------------------------------------------------------- /src/editing_workflows/animation/README.md: -------------------------------------------------------------------------------- 1 | ## Animation 2 | 3 | The *Animation* system lets you play animations on entities. You can also create complicated 4 | animation blends, crossfades, and transitions using an *Animation State Machine*. 5 | 6 | The animation system adds two new assets to The Machinery: *Animation Clip* and *Animation State 7 | Machine* as well as two new components: *Animation Simple Player* and *Animation State Machine*. 8 | 9 | To get an animation into *The Machinery* you first export it from your DCC tool as FBX or another 10 | suitable file format. Then you import this using **File > Import...**. 11 | 12 | An *Animation Clip* is an asset created from an imported DCC animation asset that adds some 13 | additional data. First, you can set a range of the original animation to use for the clip, so you 14 | can cut up a long animation into several individual clips. Second, you can specify whether the 15 | animation should loop or not as well as its playback speed. You can use a negative playback speed to 16 | get a "reverse" animation. 17 | 18 | Finally, you can specify a "locomotion" node for the animation. If you do, the delta motion of that 19 | node will be extracted from the animation and applied to the *entity* that animation is played on, 20 | instead of to that bone. This lets an animation "drive" the entity and is useful for things like 21 | walking and running animations. The locomotion node should typically be the root node of the 22 | skeleton. If the root mode is animated and you "don't" specify a locomotion node, the result will be 23 | that the root node "walks away" from the animation. 24 | 25 | 28 | 29 | The *Animation Simple Player Component* is a component that you can add to an entity to play 30 | animations on it. The component lets you pick a single animation to play on the entity. This is 31 | useful when you want to play simple animations such as doors opening, coins spinning, flags waving, 32 | etc. If you want more control over the playback and be able to crossfade and blend between 33 | animations you should use an *Animation State Machine* instead. 34 | -------------------------------------------------------------------------------- /src/editing_workflows/import_projects.md: -------------------------------------------------------------------------------- 1 | # Import Projects 2 | 3 | The Machinery allows to share and remix the content of projects made within the Engine via the import project feature. 4 | 5 | *Project Import* provides an easy way to import assets from one The Machinery project to another. To use it, select **File > Import File…** and pick a The Machinery project file to import. The project you select is opened in a new *Import Project* tab and from there, you can simply drag-and-drop or copy/paste assets into your main project’s *Asset Browser*. 6 | 7 | ![Importing assets from another project.](https://ourmachinery.com/images/beta_20_11__import_project.png) 8 | 9 | *Importing assets from another project.* 10 | 11 | When you drag-and-drop or copy-paste some assets, all their dependencies are automatically dragged along so that they are ready to use. 12 | 13 | Here is a video showing this in action. We start with a blank project, then we drag in a level from the physics sample and a character from the animation sample, put them both in the same scene, and play: 14 | 15 | 16 | To make it even easier to share your stuff, we’ve also added **File > Import from URL…** This lets you import any file that The Machinery understands: GLTF, FBX, JPEG, or a complete The Machinery project directly from an URL. You can even import zipped resource directories in the same way. 17 | 18 | For example, in the image below, we imported a Curiosity selfie from NASA (using the URL [https://www.nasa.gov/sites/default/files/thumbnails/image/curiosity_selfie.jpg](https://www.nasa.gov/sites/default/files/thumbnails/image/curiosity_selfie.jpg) ) and dropped it into the scene we just created: 19 | 20 | ![JPEG imported from URL.](https://ourmachinery.com/images/beta_20_11__import_jpeg.png) 21 | 22 | *JPEG imported from URL.* 23 | 24 | Have you made something interesting in *The Machinery* that you want to share with the world? Save your project as an *Asset Database* and upload it to a web server somewhere. 25 | 26 | Other people can use the *Import from URL…* option to bring your assets into their own projects. 27 | 28 | > **Note**: Be aware when you download plugins from the internet, they might contain plugin assets. Only Trust them if you can trust the source! More on this [See Plugin Assets]({{base_url}}extending_the_machinery/plugin-assets.html) 29 | 30 | -------------------------------------------------------------------------------- /src/editing_workflows/prototype_workflow/how_to_create_prototypes.md: -------------------------------------------------------------------------------- 1 | # Creating Prototype Assets 2 | 3 | This walkthrough shows you how to create *Prototype Assets*. 4 | 5 | *Prototypes* act as "templates" or "prefabs" for other assets. When you instantiate a prototype, the instance will inherit all the properties of the prototype unless you specifically override them. 6 | 7 | In The Machinery there is no distinction between "prototype assets" and "ordinary assets". Any asset can be used as a prototype for other assets. The prototype system is also hierarchical. I.e., prototypes may themselves have prototypes. This lets you mix and match assets in lots of interesting ways. 8 | 9 | ## Create a Prototype as a New Asset 10 | 11 | In The Machinery, the assets most commonly used as prototypes are: 12 | 13 | - Entities 14 | - Entity Graphs 15 | - Creation Graphs 16 | 17 | Since prototypes are just an ordinary assets, you can create an empty prototype, by creating an asset of the desired type in the Asset Browser: **Right Click → New → Entity/Entity Graph/Creation Graph**. 18 | 19 | This will add a new asset to your project. Any changes made to the asset will be applied to all instances of the prototype. 20 | 21 | ## Entity Prototype: Drag and Drop 22 | 23 | You can create a Prototype from an Entity by simply dragging and dropping it from the Entity Tree into the Asset Browser. 24 | 25 | ![](https://www.dropbox.com/s/erc3f4wqjoy5djt/tm_tut_prototype_create_drag.png?raw=1) 26 | 27 | This creates a new asset with the file extension `.entity`. It also replaces the entity in the Entity Tree with an instance of the newly created prototype. 28 | 29 | ## Entity Prototype: Create Prototype from Entity 30 | 31 | You can also create a prototype by using the context menu in the Entity Tree View on the Entity you want to turn into a Prototype: 32 | 33 | ![](https://www.dropbox.com/s/ys17wsljt82s2me/tm_tut_prototype_create_context.png?raw=1) 34 | 35 | 36 | 37 | ## Graph Prototypes from Subgraphs 38 | 39 | You can turn a Subgraph into a prototype by choosing **Create Subgraph Prototype** in the Subgraph node's context menu. This creates a Subgraph Prototype Asset (`.entity_graph`) in your Asset Browser. It will also change the Subgraph to become an instance of the newly created prototype. If you open the Subgraph node at this point all the nodes will be grayed out. This shows that they are inherited from the prototype. Any changes you make there will be local to that instance. 40 | 41 | To make a change that propagates to all instances of the prototype, open the prototype in the asset browser, or by using the **Open Prototype** button in the Properties view of the Subgraph node. 42 | 43 | ![](https://www.dropbox.com/s/kstww1jbo3dpvwj/tm_guide_entity_graph_create_subgraph_prototype.gif?raw=1) 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/editing_workflows/prototype_workflow/how_to_instantiate_prototypes.md: -------------------------------------------------------------------------------- 1 | # Instantiating Prototypes 2 | 3 | How you create prototype instances depend on what kind of prototype you want to instance. 4 | 5 | 6 | 7 | ## Entity Prototypes 8 | 9 | To create an instance of an entity prototype, you can simply drag an drop the entity from the Asset Browser into the Entity Tree or the Scene Tab: 10 | 11 | ![](https://www.dropbox.com/s/hxrfnyppjfrzrjg/tm_tut_prototype_entity_drag.png?raw=1) 12 | 13 | You can also use the context menu in the Entity Tree to replace any entity with an instantiated asset: 14 | 15 | ![](https://www.dropbox.com/s/7977n6966p9qhbh/tm_tut_prototype_replace_asset.png?raw=1) 16 | 17 | At runtime, you can create instances of an entity asset by spawning them from the Entity Graph: 18 | 19 | ![](https://www.dropbox.com/s/n5h5art3g8ws53y/tm_tut_prototype_spawn_entity.png?raw=1) 20 | 21 | 22 | 23 | ## Subgraph Prototypes 24 | 25 | You can add an instance of a Subgraph by dropping the `.graph` asset from the Asset Browser into the Graph editor. 26 | 27 | Note that the dropped graph must be of the same type as the graph you are editing. I.e. Creation Graph Subgraphs can only be used in Creation Graphs, Entity Graph Subgraphs can only be used in Entity Graphs. 28 | 29 | ![](https://www.dropbox.com/s/zf0vgfw6jm3yj09/tm_tut_prototype_subgraph_drag.png?raw=1) 30 | 31 | Another way of creating an instance of a Subgraph is to create an empty Subgraph node in the Graph and then picking a prototype for it in the Properties view: 32 | 33 | ![](https://www.dropbox.com/s/cdmcftplipgysx5/tm_tut_prototype_subgraph_node.png?raw=1) 34 | 35 | 36 | 37 | ## Creation Graph Prototypes 38 | 39 | The Render Component and other components that make use of Creation Graphs typically let you specify the prototype to use for the Creation Graph in the Properties View: 40 | 41 | ![](https://www.dropbox.com/s/duklb4r264uqrt5/tm_tut_prototype_creation_graph.png?raw=1) 42 | 43 | The **Edit** button in this view lets you open the specific Creation Graph instance used by this component for editing. -------------------------------------------------------------------------------- /src/editing_workflows/publish.md: -------------------------------------------------------------------------------- 1 | ## Publishing your game 2 | 3 | You publish your game via **File -> Publish**. The Engine opens the publishing tab. 4 | 5 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625575509478_image.png) 6 | 7 | In there, you have a couple of options: 8 | 9 | | Option | Description | 10 | | ----------------- | ------------------------------------------------------------ | 11 | | Executable Name | The name of the executable, e.g. `test.exe` | 12 | | Window Title | The text which is displayed in the window title. | 13 | | World Entity | The Entry point of your game. | 14 | | Resolution | The default resolution to use when running the published project | 15 | | Fullscreen | If checked the game will launch in Fullscreen | 16 | | Directory Project | Decides if the game data is published as binary data or as human readable directory. | 17 | 18 | 19 | 20 | 21 | 22 | **Directory vs. none Directory Project** 23 | 24 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625575521208_image.png) 25 | 26 | 27 | If you check this option, the game is exported as a human-readable project. Otherwise the game data will be compressed and stored in a binary `.the_machinery` format. 28 | 29 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625575817141_image.png) 30 | 31 | 32 | > Not recommended for other than debug purposes. 33 | 34 | -------------------------------------------------------------------------------- /src/editing_workflows/sculpting.md: -------------------------------------------------------------------------------- 1 | ## Sculpt Tool 2 | 3 | > **Note:** This tool is in a preview state. 4 | 5 | With the Sculpt Tool The Machinery supports rapid prototyping when it comes to level white boxing. You make use of the tool by adding a Sculpt Component to an Entity. Using the sculpt component you can quickly sketch out levels or make beautiful blocky art: 6 | 7 | ![A blocky character in a blocky forest setting.](https://ourmachinery.com/images/beta_20_11__blocky.png) 8 | 9 | *A blocky character in a blocky forest setting.* 10 | 11 | ## How to use the Tool 12 | 13 | To use the Sculpt Component, first add it to an entity, by right-clicking the entity in the *Entity Tree* and selecting *Add Component.* Then, select the newly created *Sculpt* component in the *Entity Tree*. 14 | 15 | This gives you a new sculpt tool in the toolbar: 16 | 17 | ![Sculpt tool.](https://ourmachinery.com/images/beta_20_11__sculpt_tool.png) 18 | 19 | *Sculpt tool.* 20 | 21 | With this tool selected, you can drag out prototype boxes on the ground. You can also drag on an existing prototype box to create boxes attached to that box. 22 | 23 | The standard *Select*, *Move*, *Rotate,* and *Scale* tools can be used to move or clone (by shift-dragging) boxes. 24 | 25 | You can add physics to your sculpts, by adding a *Physics Shape Component*, just as you would for any other object. 26 | 27 | > **Note**: If you are cooking a physics mesh or convex from your sculpt data, you need to explicitly recook whenever the sculpt data changes. 28 | 29 | Here is a video of sculpting in action: 30 | 31 | 32 | 33 | > **Note:** Currently, all the sculpting is done with boxes. We may add additional shape support in the future. 34 | 35 | ## Additional though 36 | 37 | In addition to being a useful tool, the *Sculpt Component* also shows the deep integration you can get with custom plugins in The Machinery. The *Sculpt Component* is a separate plugin, completely isolated from the rest of The Machinery and if you wanted to, you could write your own plugins to do similar things. -------------------------------------------------------------------------------- /src/editing_workflows/shaders_materials.md: -------------------------------------------------------------------------------- 1 | # Meshes / Materials / Shaders 2 | 3 | In the Machinery Creation Graphs represent Meshes, Materials and Shaders all at the same time. 4 | 5 | {{#include ../creation_graphs/concept.md:2:*}} 6 | -------------------------------------------------------------------------------- /src/editing_workflows/simulation.md: -------------------------------------------------------------------------------- 1 | ## Simulation 2 | 3 | In *The Machinery*, we make a distinction between *simulating* and *editing*. When you are *editing*, 4 | you see a static view of the scene. All the runtime behaviors like physics, animation, destruction, 5 | entity spawning, etc are disabled. (Editing the scene with everything moving around would be very 6 | tricky.) 7 | 8 | In contrast, when you are *simulating* or *running*, all the dynamic behaviors are enabled. This 9 | allows you to see the runtime behavior of your entities. If you are building a game, the simulation 10 | mode would correspond to running the game. 11 | 12 | To *simulate* a scene, open a scene in the *Simulate* tab. 13 | 14 | ![Simulate tab.](https://www.dropbox.com/s/7t8elpzqllqkqrb/simulate-tab.png?raw=1) 15 | 16 | You can use the controls in the tab to pause, play, or restart the simulation or change the 17 | simulation speed. Note that if you haven't added any simulation components to the scene, the 18 | *Simulate* tab will be just as static as the Scene tab. In order to get something to happen, you 19 | need to add some runtime components. 20 | 21 | The *Entity Graph* gives you a visual scripting language for controlling entity behavior. It will 22 | be described in the next section. 23 | 24 | You can launch the engine in simulation mode from the command line: 25 | 26 | ``` 27 | the-machinery.exe --load-project project.the_machinery --simulate scene 28 | ``` 29 | 30 | Here `project.the_machinery` should be the name of your project file and `scene` the name of the 31 | entity you want to simulate. This will open a window with just the *Simulate* tab, simulating the 32 | scene that you specified. 33 | -------------------------------------------------------------------------------- /src/editing_workflows/sound.md: -------------------------------------------------------------------------------- 1 | ## Sound 2 | 3 | The Machinery comes with a low-level sound system that can import WAV files into the project and 4 | play them back. The sound system can position sounds in 3D space and mix together 2D and 3D sounds 5 | for output on a stereo, 5.1, or 7.1 sound system. 6 | 7 | You can play a sound by adding a *Sound Source Component* to an object in the level of by using one 8 | of the sound playing nodes in the visual scripting language. 9 | 10 | 11 | 12 | ### Missing features 13 | 14 | The sound system is rudimentary. Here are some features that are planned for the future: 15 | 16 | * Sound streaming 17 | * Sound compression 18 | * WASAPI backend 19 | * React to the user plugging in or unplugging headphones 20 | * Hermite-interpolated resampling 21 | * Reverb 22 | * Directional sound sources 23 | * Doppler effect 24 | * Multiple listeners 25 | * HRTF 26 | * High-level sound system 27 | * Random sounds 28 | * Composite sounds 29 | * Streaming sounds 30 | * Compressing sounds 31 | -------------------------------------------------------------------------------- /src/editing_workflows/visual-scripting.md: -------------------------------------------------------------------------------- 1 | ## Entity Graphs 2 | 3 | The *Entity Graph* implements a visual scripting language based on nodes and connections. To use 4 | it, right-click on an entity to add a Graph Component and then double click on the Graph Component 5 | to open it in the Graph Editor: 6 | 7 | ![Graph editor.](https://www.dropbox.com/s/ssasbp5sb0vq7gy/graph-editor.png?raw=1) 8 | 9 | The visual scripting language uses *Events* to tick the execution of nodes. For example, the 10 | *Tick Event* node will trigger its out connector whenever the application ticks its frame. Connect 11 | its output event connector to another node to run that node during the application's update. 12 | 13 | Nodes that just fetch data and don't have any side-effects are considered "pure". They don't have 14 | any event connectors and will run automatically whenever their data is needed by one of the non-pure 15 | nodes. Connect the data connectors with wires to pass data between nodes. 16 | 17 | In addition to connecting wires, you can also edit input data on the nodes directly. Click a node 18 | to select it and edit its input data in the properties. 19 | 20 | There are a lot of different nodes in the system and I will not attempt to describe all of them. 21 | Instead, here is a simple example that adds a super simple animation to an entity using the graph 22 | component: 23 | 24 | 25 | 26 | ## What is next? 27 | 28 | For more information go and checkout the [Gameplay Coding / Visual Scripting Chapter]({{base_url}}/gameplay_coding/visual_scripting/index.html) 29 | 30 | For more examples, check out the `pong` and `animation` projects in the samples. 31 | 32 | -------------------------------------------------------------------------------- /src/extending_the_machinery/README.md: -------------------------------------------------------------------------------- 1 | # Extending The Machinery 2 | 3 | In The Machinery, **everything is a [plugin]({{base_url}}extending_the_machinery/the_plugin_system.html)**. You can **extend**, **modify** or **replace** existing engine functionality with your plugins. 4 | 5 | The Engine explicitly aims to be simple, minimalistic, and easy to understand. All our code is written in plain C, a significantly more straightforward language than modern C++. The entire codebase compiles in less than 30 seconds, and we support hot-reloading of DLLs, allowing for fast iteration cycles. You can modify your plugin code while the editor or the game runs since the plugin system supports [hot-reloading]({{base_url}}extending_the_machinery/hot-reloading.html). In short, we want to be "hackable." Our APIs are exposed as C interfaces, which means you can easily use them from C, C++, D, or any other language with an FFI for calling into C code. 6 | 7 | 8 | 9 | **Guides to follow:** 10 | 11 | - Basic understanding on how to [write a plugin]({{base_url}}extending_the_machinery/write-a-plugin.html). 12 | - Basic understanding about [gameplay coding]({{base_url}}gameplay_coding/index.html). 13 | - More complex tutorials about custom plugins check out the [Tutorials Book]({{base_url}}) 14 | 15 | -------------------------------------------------------------------------------- /src/extending_the_machinery/application_hooks.md: -------------------------------------------------------------------------------- 1 | # Application Hook's 2 | 3 | The Machinery allows you to hook your code into specific customization points. Those points happen in different phases and have specific purposes. The biggest difference between the Runner and the Editor is that only the customization points differ in the central update loop. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | 10 | ## Application Create 11 | 12 | ![](https://www.dropbox.com/s/vsl0d53ty9rsvbi/tm_guide_app_hook_create.png?raw=1) 13 | ## Update 14 | 15 | **Important side note** here `tm_plugin_tick_i` should **not** be used for **gameplay**. To manage your gameplay you should rely on the given gameplay hooks: 16 | 17 | - Entity Component Systems 18 | - Entity Component Engines 19 | - Simulation Entry 20 | 21 | They are the only recommended way of handling gameplay in the Engine. 22 | 23 | > **Note:** Plugin reloads only happen if a plugin has been identified as replaced. 24 | 25 | ### Editor 26 | 27 | ![](https://www.dropbox.com/s/ibyjx33p4lci62w/tm_guide_app_hooks_update_editor.png?raw=1) 28 | 29 | ### Runner 30 | 31 | ![](https://www.dropbox.com/s/9nq4ysh2gefzks1/tm_guide_app_hooks_update_runner.png?raw=1) 32 | 33 | ## Project Hooks 34 | 35 | ![](https://www.dropbox.com/s/jtsk5df9rykp8di/tm_guide_app_hook_project.png?raw=1) 36 | 37 | ## Application Shutdown 38 | 39 | ![](https://www.dropbox.com/s/ecssnn4hvv42avi/tm_guide_app_hook_shutdown.png?raw=1) 40 | 41 | ## Overview 42 | 43 | | Interface | Description | 44 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 45 | | `TM_DLL_EXPORT void tm_load_plugin(struct tm_api_registry_api *reg, bool load)` | Entry point for all plugins | 46 | | `tm_plugin_init_i` | Is typically called as early as possible after all plugins have been loaded. **Is not called when a plugin is reloaded.** | 47 | | `tm_plugin_set_the_truth_i` | Is called whenever the "main" Truth of the application changes. The "main" Truth is the primary Truth used for editing data in the application. **Under API Review** | 48 | | `tm_render_pipeline_vt` | | 49 | | `tm_the_machinery_project_loaded_i` | Is called when a project is loaded. | 50 | | `tm_plugin_reload_i` | Is called whenever plugins are reloaded after the reload finishes. | 51 | | `tm_plugin_tick_i` | Is typically called as early as possible in the application main loop "tick". | 52 | | A tab that is registered to `tm_tab_vt` and has a `tm_tab_vt.ui()` or `tm_tab_vt.hidden_update()` function. | Interface name for the tab `vtable`. Any part of the UI that can act as a tab should implement this interface. | 53 | | `tm_entity_register_engines_simulation_i_version` Is called at the beginning of a simulation (start up phase) and all Systems / Engines are registered to the entity context. `tm_entity_system_i.update()` or `tm_engine_i.update()` | Used to register a `tm_entity_register_engines_i` that should run in simulation mode with. More information in the designated chapter. [Entity Component System]({{base_url}}gameplay_coding/ecs/index.html) | 54 | | `tm_entity_register_engines_editor_i_version` | Used to register a `tm_entity_register_engines_i` that should run in editor mode with. | 55 | | `tm_simulation_entry_i` `tm_simulation_entry_i.start() ` `tm_simulation_entry_i.tick()` `tm_simulation_entry_i.stop()` | The Simulation Entry interface `tm_simulation_entry_i` makes it possible to choose a point of entry for code that should run while the simulation (simulation tab or runner) is active. More information in the designated chapter. [Simulation Entry]({{base_url}}/gameplay_coding/simulation_entry.html) | 56 | | `tm_the_machinery_project_unloaded_i` | Is called when a project is unloaded. | 57 | | `tm_the_machinery_project_saved_i` | Is called when a project is saved. | 58 | | `tm_plugin_shutdown_i` | Is called when the application shutdowns on all plugins that have an interface registered. **Is not called when a plugin is reloaded.** | -------------------------------------------------------------------------------- /src/extending_the_machinery/hot-reloading.md: -------------------------------------------------------------------------------- 1 | # Hot-Reloading 2 | 3 | We support hot-reloading of plugins while *The Machinery* is running. This allows you to work on a 4 | plugin and see the changes in real-time without having to shut down and restart the application 5 | between each change to your code. 6 | 7 | Hot-reloading is enabled by default, but can be disabled with the `--no-hot-reload` parameter. 8 | 9 | When a reload happens, the function pointers in the plugin's API struct are replaced with function 10 | pointers to the new code. Since clients hold pointers to this struct, they will use the new function 11 | pointers automatically -- they don't have to re-query the system for the API. 12 | 13 | Note that hot-reloading is not magical and can break in a lot of situations. For example, if you 14 | remove functions in the API or change their parameters, any clients of your API will still try to 15 | call them using the old parameter lists, and things will most likely crash. Similarly, if a client 16 | has stashed away a function pointer to one of your API functions somewhere, such as in a list of 17 | callbacks, there is no way for us to patch that copy and it will continue to call the old code. 18 | Also, if you make changes to the layout of live data objects (such as adding or removing struct 19 | fields) things will break because we make no attempts to transfer the data to the new struct 20 | format. 21 | 22 | But adding or removing static functions, or changing the code inside functions should work without 23 | problems. We find hot-reloading to be a big time saver even if it doesn't work in all circumstances. 24 | 25 | If you want to use global variables in your DLL you should do so using the 26 | `tm_api_registry_api->static_variable()` function in your `tm_load_plugin()` code. If you just 27 | declare a global variable in your .c file, that variable will be allocated in the DLLs memory space 28 | and when the DLL is reloaded you will lose all changes to the variable. When you use 29 | `static_variable()`, the variable is allocated on the heap, and its content is preserved when the 30 | DLL is reloaded. 31 | 32 | If you are using hot-reloading together with a debugger on Windows, be aware that the debugger will 33 | lock `.pdb` files which will prevent you from rebuilding your code. The suggested workflow is 34 | something like this: 35 | 36 | * Detach the debugger if it's currently attached. 37 | * Rebuild your DLL and fix any compiler bugs. 38 | * When the DLL is built successfully, The Machinery will automatically reload it. 39 | * If you need to continue debugging, re-attach the debugger. 40 | -------------------------------------------------------------------------------- /src/extending_the_machinery/plugin-assets.md: -------------------------------------------------------------------------------- 1 | # Plugin assets 2 | 3 | When you put a plugin in the `plugin` folder, it will be loaded every time you start The Machinery 4 | and used by all projects. This is convenient, but sometimes you want plugins that are project 5 | specific, e.g., the gameplay code for a particular game. 6 | 7 | **Table of Content** 8 | 9 | * {:toc} 10 | 11 | 12 | ## The two ways of achieving plugin only assets 13 | 14 | There are two ways of doing this. 15 | 16 | First, you could create a separate The Machinery executable folder for that specific project. Just 17 | make a copy of the The Machinery folder and add any plugins you need. Whenever you want to work on 18 | that project, make sure to start that executable instead of the standard one. 19 | 20 | In addition to adding project specific plugins, this method also lets you do additional things, 21 | such as using different versions of The Machinery for different projects and remove any of the 22 | standard plugins that you *don't* need in your project. 23 | 24 | The second method is to store plugins as *assets* in the project itself. To do this, create a *New 25 | Plugin* in the *Asset Browser* and set the DLL path of the plugin to your DLL. We call this a 26 | *Plugin Asset*. 27 | 28 | The *Plugin Assets* will be loaded whenever you open the project and unloaded whenever you close 29 | the project. Since the plugin is distributed with the project, if you send the project to someone, 30 | they will automatically get the plugin too -- they don't have to manually install into their 31 | `plugin` folder. This can be a convenient way of distributing plugins. 32 | 33 | > **WARNING: Security Warning** 34 | > 35 | > Since plugin assets can contain arbitrary code and there is no sandboxing, when you run a 36 | > plugin asset, it will have full access to your machine. Therefore, you should only run plugin 37 | > assets from trusted sources. When you open a project that contains plugin assets, you will 38 | > be asked if you want to allow the code to run on your machine or not. You should only click 39 | > *[Allow]* if you trust the author of the project. 40 | 41 | > **NOTE: Version Issues** 42 | > 43 | > Since The Machinery is still in early adopters mode and doesn't have a stable API, plugins will only work 44 | > with the specific version they are developed for. If you send a plugin to someone else 45 | > (for example as a plugin asset in a project), you must make sure that they use the exact same 46 | > version of The Machinery. Otherwise, the plugin will most likely crash. 47 | 48 | ## How to create a plugin asset 49 | 50 | You can create a plugin asset in the Asset Browser. **Righ Click -> New -> New Plugin**. This will create a plugin asset in your asset browser. On its own this is quite useless. When you select it you can set the DLL Path for your plugin on windows or on linux. The moment you have selected the path to the dll. It will be imported and stored in the asset. 51 | 52 | > **Note:** The asset plugin will store the path absolute. 53 | 54 | The plugin asset settings look as following: 55 | 56 | ![](https://www.dropbox.com/s/hc12tcagz448ffz/tm_guide_plugin_asset.png?raw=1) 57 | 58 | You would have to repeat the above described workflow every time you change the code of your plugin. This is very annoying, but do not worry hot-reloading comes to rescue! 59 | 60 | You can enable hot-reload for plugin assets by checking the ***Import When Changed* checkbox (1)** in the plugin 61 | properties. If checked, the editor will monitor the plugin's import path for changes and if it 62 | detects a file change, it will reimport the plugin. 63 | 64 | The **Windows & Linux DLL Path (2)** can be used to provide the path to the DLLs for the importing the plugin. Plugin Assets need to obey the same rules as normal plugins. Therefore they need to provide the `TM_DLL_EXPORT void tm_load_plugin(struct tm_api_registry_api *reg, bool load)` function. In case this is not possible because the DLL is a helper the helper check box can be called. 65 | -------------------------------------------------------------------------------- /src/gameplay_coding/README.md: -------------------------------------------------------------------------------- 1 | # Gameplay Coding in The Machinery 2 | 3 | In this section, you will learn the basics about Gameplay Coding in *The Machinery.* There are two primary ways of creating a vivid and active world: 4 | 5 | - Using our C APIs [API Documentation]({{docs}}apidoc.html). 6 | - Using the [Visual Scripting Language]({{base_url}}editing_workflows/visual-scripting.html), which you can extend as well. 7 | 8 | ## Coding within our Entity Component System 9 | 10 | The Machinery uses an Entity Component System; therefore, most of your gameplay code will run via Engines or Systems. To learn more about these, please follow this [link]({{base_url}}/gameplay_coding/ecs/index.html). 11 | 12 | ## General code entry points using Simulation Entry Component 13 | 14 | The Machinery also offers you a Simulation Entry Component which will, when the parent entity is spawned, set up a system with that is used to run code at start-up and each frame. Read more [here]({{base_url}}gameplay_coding/simulation_entry.html). -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/filtering_entities.md: -------------------------------------------------------------------------------- 1 | # Filtering Entities 2 | 3 | The Machinery knows 2 kind of ways to Tag Entities: 4 | 5 | 1. using the `Tag Component` 6 | 2. using a `Tag Component` to filter the Entity Types 7 | 8 | 9 | 10 | **Table of Content** 11 | 12 | * {:toc} 13 | ## Filtering Entities 14 | 15 | In an Engine (`tm_engine_i`) you can define the `.excluded` field. This tells the scheduler that this engine shall **not** run on any entity type that contains these components. 16 | 17 | Let us assume we have the following entities: 18 | 19 | ``` 20 | #1 Entity: 21 | - Component A 22 | - Component B 23 | - Component C 24 | #2 Entity: 25 | - Component A 26 | - Component B 27 | - Component D 28 | ``` 29 | 30 | Now we have an Engine that shall operate on `(Component A,Component B)` but we do not want it to operate on entities with `Component D` we could just check in our update loop: 31 | 32 | ```c 33 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_filtering_entities.c,entity_register_engines)}} 34 | ``` 35 | 36 | or we could define a component mask and use this to filter but both methods are slow. This is because `get_component_by_hash` or `get_component` require us to look up internally the entity + the components and search for them. Its aka a random memory access! 37 | 38 | To avoid all of this we can just tell the engine to ignore all entity types which contain the `component_d` via the `.excluded` field in the `tm_engine_i`. 39 | 40 | ```` c 41 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_filtering_entities.c,tm_engine_i)}} 42 | ```` 43 | 44 | ## Filtering Entities by using Tag Components 45 | 46 | > **Note**: You can define a `Tag` Component which should not be confused with the `Tag Component`. A tag component is a simple typedef of a `unit64_t` (or something else) or an empty struct in C++ to a component without properties. The function of this component is it to modify the Entity Type / Archetype to group entities together with them.For more information see the [Tagging Entities]({{base_url}}/gameplay_coding/ecs/tagging_entities.html) Chapter. 47 | 48 | You have a Movement / Input System which should always work. At some point you do not want an entity to receive any input. 49 | 50 | *Solution 1* 51 | 52 | To solve this issue you could remove the Movement Component but that would be annoying because you would loose its state, which might be important. 53 | 54 | *Better Solution* 55 | 56 | First you define the component: 57 | 58 | ```c 59 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_filtering_entities.c,component__create)}} 60 | ``` 61 | 62 | Then you filter in your update for the Input Engine/ Movement Engine any Entity that has a No Movement Tag: 63 | 64 | ```c 65 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_filtering_entities.c,register_engine)}} 66 | ``` 67 | 68 | Whenever another `engine/system` decides that an entity should not move anymore it just adds a `no_movement_tag_component` to the entity. 69 | 70 | ```c 71 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_filtering_entities.c,engine_update)}} 72 | ``` 73 | 74 | As you can see the Movement Engine will now update all other entities in the game which do not have the No Movement Tag. -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/how_to_define_a_engine_system.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Defining a System and Engines 4 | 5 | You have to pass the `tm_entity_system_i` or `tm_engine_i` instance in your register function. 6 | 7 | **Table of Content** 8 | 9 | * {:toc} 10 | ## Ask yourself those questions before you design an Engine / System 11 | 12 | The following questions are better explained in the chapter: [How entities can interact.]({{base_url}}/gameplay_coding/ecs/how_entites_can_interact.html) 13 | 14 | - On what data do we operate? 15 | - What is our domain? 16 | - What is the possible input for our transformation? 17 | - What is the usage frequency of the data? 18 | - What are we actually transforming? 19 | - What could our algorithm look like? 20 | - How often do we perform our transformation? 21 | 22 | and my answers 23 | 24 | - What kind of data am I going to read? 25 | - What kind of data am I going to write? 26 | - What kind of data do I want to ignore? (**only important for engines**) 27 | - Should my operation be exclusive? Hence not to be executed in parallel? 28 | - In which phase does it run? 29 | - What dependencies do I have? 30 | 31 | Now it is time to define the dependencies / important items for scheduling. 32 | 33 | 34 | 35 | ### How do those questions translate? 36 | 37 | 38 | 39 | **What kind of data am I going to read? && What kind of data am I going to write?** 40 | 41 | They translate `.write` and `.components.` With those fields, we tell the scheduler what components this system operates. From which components it intends to read from and to which one it writes. 42 | 43 | **What kind of data do I want to ignore?** (only important for engines) 44 | 45 | In the `tm_engine_i` you can provide a way to filter your component. Thus you can decide on which components the engine shall run. The field `.excluded` is used for this in there you can define which components an entity type shall **not** have. This means that when the engine is scheduled all entities will be ignored with those components. 46 | 47 | For more information see [Tagging Entities]({{base_url}}/gameplay_coding/ecs/tagging_entities.html) and [Filtering Entities]({{base_url}}/gameplay_coding/ecs/filtering_entities.html) 48 | 49 | **Should my operation be exclusive? Hence not to be executed in parallel?** 50 | 51 | If we are sure that our system/engine should not run parallel, we need to tell the scheduler by setting the `.exclusive` flag to true. It will not run in parallel with any other systems or engines in the entity context. If it is **false** then the components and writes will be used to determine parallelism. 52 | 53 | **In which phase does it run?** 54 | 55 | We can define the `.phase` to tell the system in which phase we want our operation to run. 56 | 57 | **What dependencies do I have?** 58 | 59 | We can define dependencies by saying: `.before_me` and `.after_me`. We just pass the string hash of the other engine/system to this, and the scheduler does the rest. 60 | 61 | 62 | 63 | ## What is next? 64 | 65 | In the next chapter we translate this to actual code! 66 | -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/how_to_design_system_or_engine.md: -------------------------------------------------------------------------------- 1 | # How to design a Systems & Engines 2 | 3 | In the Machinery, you provide the behavior for your gameplay code via Engines and Systems. The difference between Engines and Systems is that Engines provide an explicitly defined subset of components while Systems give you only access to the Entity Context. 4 | 5 | > **Note:** Unsure what a System or an Engine is? Please read [here]({{base_url}}/gameplay_coding/ecs/index.html) 6 | 7 | This separation means that Engines are better used for high-frequency operations on many entities. At the same time, Systems are better used for broader operations such as input on a few Entities / Single entities. 8 | 9 | 10 | 11 | > **Documentation:** The difference between *engines* and *systems* is that engines are fed component data, whereas systems are not. Thus, systems are useful when the data is stored externally from the components (for example to update a physics simulation), whereas *engines* are more efficient when the data is stored in the components. (You could use a *system* to update data in components, but it would be inefficient, because you would have to perform a lot of lookups to access the component data.) 12 | 13 | 14 | 15 | These are a couple of questions you should ask yourself in advance. 16 | 17 | - On what data do we operate? 18 | - What is our domain? 19 | - What is the possible input for our transformation? 20 | - What is the usage frequency of the data? 21 | - What are we actually transforming? 22 | - What could our algorithm look like? 23 | - How often do we perform our transformation? 24 | 25 | > More details about those questions click here : [How entities can interact.]({{base_url}}/gameplay_coding/ecs/how_entites_can_interact.html) 26 | 27 | At the end of this, you should be able to answer the following questions: 28 | 29 | - What kind of data am I going to read? 30 | - What kind of data am I going to write? 31 | - Should my operation be exclusive? Hence not to be executed in parallel? 32 | - In which phase does it run? 33 | - What dependencies do I have? 34 | 35 | Those answers are important for the automatic scheduling of the Systems/Engines. Based on all those inputs, the Entity System can determine when and how to schedule what. 36 | 37 | ## Best Practice 38 | 39 | - **System/Engine Scope:** Systems should be designed to have one job only. This can be difficult at times, especially when designing new features. Therefore it is fine to first create a bigger system and then with time make them smaller. If you find that your engine/system does a lot of things, don't worry. In an ECS things are decoupled from everything else, therefore it is generally pretty easy to split them up into smaller units. This allows you to increase reusability of systems 40 | - **System/Engine Scheduling:** Always provide a write list and a list of components your Engine/System is operating on. This is important so the scheduler can do its best! Also do not forget to make use of `.before_me`, `.after_me` and `.phase` more about this in the next chapter! 41 | 42 | ## Example 43 | 44 | ```c 45 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_system_engine.c,tm_engine_i)}} 46 | ``` 47 | 48 | This movement engine will operate on: 49 | 50 | - `keyboard_component` 51 | - `movement_component` 52 | - `transform_component` 53 | - `mover_component` 54 | 55 | components. The scheduler can now look for those components in other engines and determine based on the .`write` field how to schedule it efficiently. 56 | 57 | In this example the scheduler can schedule any engine that writes to the keyboard and the movement component that the same time as this engine if they do not write to the transform and mover component! 58 | 59 | ## What is next? 60 | 61 | More details on writing your own system or engine is explained in the next chapter 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/how_to_register_a_system_or_engine.md: -------------------------------------------------------------------------------- 1 | # Registering a System or an Engine 2 | 3 | To register Systems/Engines, you need to provide a register function to the `tm_entity_register_engines_simulation_i` interface. This function has the signature: 4 | 5 | ```c 6 | static void entity_register_engines_i(struct tm_entity_context_o *ctx) 7 | ``` 8 | 9 | For more information check the `tm_entity_register_engines_simulation_i` . 10 | 11 | Whenever the Machinery creates an Entity Context, it calls this function and registers all your Systems / Engines to this context. 12 | 13 | > The Entity context is the world in which all your entities exist. 14 | 15 | For Engines, you pass an instance of the `tm_entity_system_i` to the register function. 16 | 17 | ```c 18 | // example: 19 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_system_engine.c,tm_entity_system_i)}} 20 | ``` 21 | 22 | 23 | 24 | For Systems, you pass an instance of the `tm_engine_i` to the register function. 25 | 26 | ```c 27 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_system_engine.c,entity_register_engines_i)}} 28 | ``` 29 | 30 | In the above example the scheduler will schedule this system after the `maze_generation_system` system! Since we did not provide any further information in `.writes` or in `.components` the scheduler has no other information to work with. In this case it is best to not write anything! 31 | 32 | *Example load function:* 33 | 34 | 35 | ```c 36 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/ecs_system_engine.c,tm_load_plugin)}} 37 | ``` 38 | 39 | 40 | 41 | ## Register your system or engine to the Editor 42 | 43 | You can use the `tm_entity_register_engines_simulation_i` to register your engine or system to an entity context that runs only in the Editor. This might be good for components that shall only be used in the Editor. 44 | 45 | The function signature is the same as the for the other interface! 46 | 47 | 48 | 49 | ### Register systems & engines outside of the load function 50 | 51 | You also can register your System/Engine outside of the load function wherever you have access to the correct Entity Context. 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/simulation_lifecycle.md: -------------------------------------------------------------------------------- 1 | # Overview of the Entity Context Lifecycle 2 | 3 | This page describes the lifecycle of the entity context / the simulation and all its stages. 4 | 5 | ![](https://www.dropbox.com/s/vxq89spqcwzdvy8/tm_guide_ecs_life_cycle.png?raw=1) 6 | 7 | ## Update Phases 8 | 9 | In your Engine / Systems you an define in which Phase of the Update loop, your Engine / System shall run. This can be managed via the: `.before_me`, `.after_me` and `.phase` fields of your engine or system definition. 10 | 11 | Please keep in mind that the Scheduler will order your system based on what kind of components you might modify or not! This is why it is always recommended to say what kind of components your system/engine will operate on and what they will do with them (Write to them or not). Depending on your dependencies the scheduler will decide if your engine/system can run in parallel. 12 | 13 | **The Engine has default phases:** 14 | 15 | | Name | When | 16 | | --------------------- | -------------------------------------------- | 17 | | `TM_PHASE__ANIMATION` | Phase for animation jobs. | 18 | | `TM_PHASE__PHYSICS` | Phase for physics jobs. | 19 | | `TM_PHASE__CAMERA` | Phase for camera jobs. | 20 | | `TM_PHASE__GRAPH` | Phase for the visual scripting graph update. | 21 | | `TM_PHASE__RENDER` | Phase for render jobs. | 22 | 23 | > **Note:** that phases are just string hashes and you can extend the systems with more phases if desired. -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/tagging_entities.md: -------------------------------------------------------------------------------- 1 | # Tagging Entities 2 | 3 | The Machinery knows 2 kind of ways to Tag Entities: 4 | 5 | 1. using the `Tag Component` 6 | 2. using a `Tag Component` to filter the Entity Type 7 | 8 | 9 | 10 | **Table of Content** 11 | 12 | * {:toc} 13 | ## Using the Tag Component 14 | 15 | The difference is that the first solution can be used via the `tag_component_api` and you can add Tags via the Editor to any Entity that has a Tag Component. Later on in your System or Engine you can access the Tagged Entity. 16 | 17 | > **Note:** This is not the most performant solution but an easy way for entities which do not exist many times in the world. It is a nice way to identify one or two specific entities for some specific logic. 18 | 19 | ### Adding them via The Editor 20 | 21 | You need to select an Entity and **Right Click -> Add Component** 22 | 23 | ![](https://www.dropbox.com/s/x6pntlc4u0vw9pa/tm_guide_entity_tag_add_component.png?raw=1) 24 | 25 | This will add the *Entity Tag* Component. When selected you have the chance to add Tags to the Entity by using a simple autocomplete textbox. 26 | 27 | **Beware:** The Engine will create an entity tag folder in your root folder. This is also the place where the Entity Tag API will search for the assets. 28 | 29 | ![](https://www.dropbox.com/s/ve5lr0e0qcs221e/tm_guide_entity_tag.png?raw=1) 30 | 31 | ### Adding and Accessing Tags via C 32 | 33 | You can also add tags via the `tag_component_api` but you need access to the `Tag Component Manager`. In your System or on Simulate Entry `start()`: 34 | 35 | ```c 36 | tm_tag_component_manager_o *tag_mgr = (tm_tag_component_manager_o *)tm_entity_api->component_manager(ctx, tag_component); 37 | tm_tag_component_api->add_tag(tag_mgr, my_to_tagged_entity, TM_STATIC_HASH("player", 0xafff68de8a0598dfULL)); 38 | ``` 39 | 40 | You can also receive entities like this: 41 | 42 | ```c 43 | tm_tag_component_manager_o *tag_mgr = (tm_tag_component_manager_o *)tm_entity_api->component_manager(ctx, tag_component); 44 | tm_entity_t upper_bounding_box = tm_tag_component_api->find_first(tag_mgr, TM_STATIC_HASH("upper_bounding_box", 0x1afc9d34ecb740ecULL)); 45 | ``` 46 | 47 | And than you can read the data from the entity via `get_component`. This is where you will perform a random look up and this might be slow. Therefore it is mostly recommended to use this for simple interactions where performance is not needed. 48 | 49 | > **Note:** Tags do not need to exist in the Asset Browser, therefore you can add any label to the entity. Keep in mind that they will **not** be created in the Asset Browser! 50 | 51 | 52 | 53 | ## Tag Components - Entity Type Filter 54 | 55 | On the other hand you can define a `Tag` Component which should not be confused with the previously explained `Tag Component`. A tag component is a simple typedef of a `unit64_t` (or something else) or an empty struct in C++ to a component without properties. A tag is a component that does not have any data. The function of this component is to modify the Entity Type / Archetype to group entities together with them. 56 | 57 | *Example:* 58 | 59 | You have the following components: 60 | 61 | - Component A 62 | - Component B 63 | 64 | And 2 systems : 65 | 66 | - System A 67 | - System B 68 | 69 | They both shall operate on Component A & B but have different logic based on what the Components represent. To archive this you just add a tag component to each Entity: 70 | 71 | ``` 72 | #1 Entity: 73 | - Component A 74 | - Component B 75 | - My Tag For System A 76 | #2 Entity: 77 | - Component A 78 | - Component B 79 | - My Tag for System A 80 | ``` 81 | 82 | In this example System B would not operate on both Entities if we use the `.excluded` filter to exclude `My Tag For System A` from the System. 83 | 84 | ## Filtering 85 | 86 | To see a real world application of Tag components to filter entity types checkout the next chapter: [Filtering]() 87 | 88 | 89 | -------------------------------------------------------------------------------- /src/gameplay_coding/ecs/what_are_components.md: -------------------------------------------------------------------------------- 1 | ## What are Components? 2 | 3 | They are data, that is all they are. Designing them is the most important task you will find yourself doing in an ESC driven game. The reason is that if you change a component you have to update all systems that use it. This data composed together makes up an Entity. It can be changed at runtime, in what ever way required. This data is transformed in Systems/Engines and therefore Systems/Engines provide the Behaviour of our game based on the input/output of other Systems/Engines. 4 | 5 | > **Note**: Keep in mind they do not need a Truth Representation. If they do not have one, the Engine cannot display them in the Entity Tree View. This is useful for runtime only components. 6 | 7 | - A component is defined by `tm_component_i` — it consists of a fixed-size piece of POD data. 8 | - This data is stored in a huge buffer for each entity type, and indexed by the index. 9 | - In addition, a component can have a *manager*. 10 | - The manager can store additional data for the component that doesn’t fit in the POD data — such as 11 | lists, strings, buffers, etc. 12 | 13 | You can add callbacks to the component interface which allow you to perform actions on `add` and `remove`. The general lifetime of a component is bound to the Entity Context. 14 | 15 | ![](https://www.dropbox.com/s/1d39bh17zqgeloy/tm_guide_ecs_component.png?raw=1) 16 | 17 | 18 | 19 | > **It's all about the data** 20 | > 21 | > Data is all we have. Data is what we need to transform in order to create a user experience. Data is what we load when we open a document. Data is the graphics on the screen and the pulses from the buttons on your gamepad and the cause of your speakers and headphones producing waves in the air and the method by which you level up and how the bad guy knew where you were to shoot at you and how long the dynamite took to explode and how many rings you dropped when you fell on the spikes and the current velocity of every particle in the beautiful scene that ended the game, that was loaded off the disc and into your life. Any application is nothing without its data. Photoshop without the images is nothing. Word is nothing without the characters. Cubase is worthless without the events. All the applications that have ever been written have been written to output data based on some input data. The form of that data can be extremely complex, or so simple it requires no documentation at all, but all applications produce and need data. ([Source](https://www.dataorienteddesign.com/dodmain/node3.html)) 22 | 23 | 24 | 25 | ### Best Practice 26 | 27 | - **Component Size:** Keep them small and atomic. The main reason for this is that it improves caching performance. Besides having a lot of small components allows for more reusability and compostability! Besides if they are atomic units of data, they increase their value to be reused across projects better and can provide more combinations. *The biggest disadvantage* is that small components make it harder to find them, the larger your project is. 28 | - **Complex component data:** Generally speaking you want to avoid storing complex data such as arrays or heap allocated data in a component. It is possible and sometimes not possible to avoid, but it is always good to ask yourself if it is needed. 29 | 30 | -------------------------------------------------------------------------------- /src/gameplay_coding/simulation_entry.md: -------------------------------------------------------------------------------- 1 | ## Simulation Entry (writing gameplay code in C) 2 | 3 | This walkthrough will show you how to create a _simulation entry_ and what a simulation entry is. 4 | 5 | If you wish to program gameplay using C code, then you need some way for this code to execute. You can either make lots of entity components that do inter-component communication, but if you want a more classic monolithic approach, then you can use a simulation entry. 6 | 7 | In order for your code to execute using a simulation entry you need two things. Firstly you need an implementation of the Simulation Entry interface, `tm_simulation_entry_i` (see `simulation_entry.h`) and secondly you need a Simulation Entry Component attached to an entity. 8 | 9 | Define a `tm_simulation_entry_i` in a plugin like this: 10 | 11 | ```c 12 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/simulation_entry.c,simulation_entry_i)}} 13 | ``` 14 | 15 | Where `start`, `stop` and `tick` are functions that are run when the simulation starts, stop and each frame respectively. Make sure that `id` is a unique identifier. 16 | 17 | > **Note:** There is also a plugin template available that does this, see `File -> New Plugin -> Simulation Entry` with The Machinery Editor. 18 | 19 | > **Note:** to generate the `TM_STATIC_HASH` you need to run `hash.exe` or `tmbuild.exe --gen-hash` for more info open the [hash.exe guide]({{base_url}}/build_tools/hash.html) 20 | 21 | When your plugin loads (each plugin has a `tm_load_plugin` function), make sure to register this implementation of `tm_simulation_entry_i` on the `tm_simulation_entry_i` interface name, like so: 22 | 23 | ```c 24 | tm_add_or_remove_implementation(reg, load, tm_simulation_entry_i, &simulation_entry_i); 25 | ``` 26 | 27 | When this is done and your plugin is loaded, you can add a Simulation Entry Component to any entity and select your registered implementation. Now, whenever you run a simulation (using Simulate Tab or from a Published build) where this entity is present, your code will run. 28 | 29 | The same Simulation Entry interface can be used from multiple Simulation Entry Components and their state will _not_ be shared between them. 30 | 31 | > **Note:** For more in-depth examples, we refer to the gameplay samples, they all use Simulation Entry. 32 | 33 | ## What happens under the hood? 34 | 35 | When the Simulation Entry Component is loaded within the Simulate Tab or Runner, it will set up an entity system. This system will run your start, stop and tick functions. You may then ask, what is the difference between using a Simulation Entry and just registering a system from your plugin? The answer is the lifetime of the code. If you register a system from your plugin, then that system will run no matter what entity is spawned whereas the Simulation Entry Component will add and remove the system that runs your code when the entity is spawned and despawned. 36 | 37 | 38 | 39 | ## Example: Source Code 40 | 41 | ```c 42 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/gameplay_code/simulation_entry.c)}} 43 | ``` 44 | 45 | -------------------------------------------------------------------------------- /src/gameplay_coding/visual_scripting/debugger.md: -------------------------------------------------------------------------------- 1 | # Debugger 2 | 3 | The Entity Graph has a Debugger. You can use this Debugger to inspect the current values or set a breakpoint to see if the Graph behaves the way it should. Besides the graph indicated if a node is executed by a highlighted border! 4 | 5 | > **Note:** The Debugger only works if the simulate tab and the graph tab are open at the same time! 6 | 7 | ![](https://www.dropbox.com/s/80ld50b4n6ohjio/tm_guide_entity_graph_debugger_basic.png?raw=1) 8 | 9 | You can find the Debugger when you click on the button in the upper toolbar with the bug symbol **(1)**. It will open the Debugger Overlay. Besides the "Bug" button, you can find a dropdown menu **(2)**. This dropdown menu lets you switch between Graph instances quickly. This is useful if the Graph is part of an Entity Prototype or itself a Subgraph prototype! 10 | 11 | 12 | 13 | ## Debug Overlay 14 | 15 | ![](https://www.dropbox.com/s/wly93rk8vz97upm/tm_guide_entity_graph_debug_overlay.png?raw=1) 16 | 17 | In this overlay, you find three-tab: 18 | 19 | 1. **Watch Wires;** Contains all data wires you are watching. 20 | 2. **Breakpoints;** This Contains a list of all Breakpoints within this Graph and its subgraph 21 | 3. **Instances;** A list of all instances of this Graph 22 | 23 | 24 | 25 | ## Watch Wires 26 | 27 | Like in a normal code editor, you can hover over any data wire and observe the values during the execution. If a value changed, it would be red, otherwise white. 28 | 29 | ![](https://www.dropbox.com/s/cw86wtsfcb8sg50/tm_guide_entity_graph_watch_wires.png?raw=1) 30 | 31 | This might be cucumber some and difficult for observing multiple wires. This is why you can add them to the watch wire list. 32 | 33 | ![](https://www.dropbox.com/s/1j09t2vxxk4t11b/tm_guide_entity_graph_add_watch_wires.png?raw=1) 34 | 35 | The Watch Wire list will indicate as well if a value has changed. You can also remove them there again and find the node with the find node button. 36 | 37 | ![](https://www.dropbox.com/s/lpx1duqf5lpee0n/tm_guide_entity_graph_watch_wires_overlay.png?raw=1) 38 | 39 | Keep in mind that this list only works within the current graph instance and its subgraph. 40 | 41 | 42 | 43 | ## Breakpoints 44 | 45 | Unlike watching wires which require no extra step, you cannot just add a breakpoint, and it will break immediately since such behaviour could be annoying. You can add breakpoints at any point in time via **Right-Click on a node** -> **Add Breakpoint.** 46 | 47 | > **Note:** You can only add breakpoints to all nodes besides Event and Query nodes. 48 | 49 | ![](https://www.dropbox.com/s/us6lrw5ad9qpcbg/tm_guide_entity_graph_add_breakpoints.png?raw=1) 50 | 51 | To activate the breakpoints, you need to connect to the Simulation by pressing the Connect Button in the Debug Overlay. 52 | 53 | ![](https://www.dropbox.com/s/34jbcvkt49814kk/tm_guide_entity_graph_connect.png?raw=1) 54 | 55 | (*Alternatively, the Breakpoint Overview will inform you that you need to connect to the Simulation)* 56 | 57 | The moment you are connected, the Simulation will react appropriately, and your breakpoints will happen. 58 | 59 | ![](https://www.dropbox.com/s/26awwgjzz93mcu4/tm_guide_entity_graph_debug_mode.png?raw=1) 60 | 61 | 1. You can disconnect from the Simulation. 62 | 2. You can continue till the next breakpoint hits. 63 | 3. You can Stepover to the next node. 64 | -------------------------------------------------------------------------------- /src/gameplay_coding/visual_scripting/subgraphs.md: -------------------------------------------------------------------------------- 1 | # Subgraphs 2 | 3 | Subgraphs are a way to organize your graph better and create smaller units. They make them easier to maintain and easy to follow. In its essence a subgraph is a graph within a graph. They are interfaced via a subgraph node. They can produce Input and Output, such as a normal node could. They can also call and react to normal Events! 4 | 5 | ## Create a subgraph 6 | 7 | You create a new subgraph by simply selecting all nodes that shall be part of the subgraph. After that, click on them with the right mouse and select Create Subgraph from the context menu**.** The subgraph will replace the selected nodes. You can change its label in the property view. By simply double click you open the subgraph. 8 | 9 | ![](https://www.dropbox.com/s/k688sg41w5507mn/tm_guide_entity_graph_create_subgraph.gif?raw=1) 10 | 11 | ## Subgraph Inputs 12 | 13 | A subgraph can have inputs and outputs. You can add them to them the same way as for a normal Graph. But you can also just connect the needed wires with the subgraph node, as the following image shows: 14 | 15 | ![](https://www.dropbox.com/s/18b2z2f1ed80ex6/tm_guide_entity_graph_create_subgraph_input_output.gif?raw=1) 16 | 17 | 18 | 19 | ## Subgraph Prototypes 20 | 21 | The Machinery's **Prototype** system allows you to create, configure, and store an Entity/Creation Graph complete with all its subgraphs, input/output nodes as a reusable Entity / Creation Graph Asset. 22 | 23 | > **Note:** Since the Entity Graph and the Creation Graph are conceptually similar the same aspects apply to them both! However this document will only focus on the Entity Graph. 24 | 25 | This Asset acts as a template from which you can create new Prototype instances in other Entity Graphs/Creation Graphs. Any edits that you make to the Asset are automatically reflected in the instances of that Graph, allowing you to easily make broad changes across your whole Project without having to repeatedly make the same edit to every copy of the Asset. 26 | 27 | > **Note:** This does not mean all Prototype instances are identical. You can override individually and add/remove nodes from them, depending on your need! 28 | 29 | 30 | 31 | ### Create a subgraph Prototype 32 | 33 | You can turn a subgraph into a prototype by simply using the context menu of the subgraph node and selecting Create Subgraph prototype. This will create a Subgraph Prototype Asset (`.entity_graph`) in your Asset Browser. When you open it you are opening the instanced version. Any change to this version will not be shared across all other versions! Only changes made to the prototype will propagate to all changes! To open a prototype you can use the "Open Prototype" Button. 34 | 35 | ![](https://www.dropbox.com/s/kstww1jbo3dpvwj/tm_guide_entity_graph_create_subgraph_prototype.gif?raw=1) 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/getting_started/README.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | To run The Machinery you need: 4 | 5 | - A 64-bit Windows 10 machine with the latest Vulkan drivers 6 | - **Or** a 64-bit Ubuntu 20.04 Linux machine with the latest Vulkan drivers (ArchLinux should also work, no guarantees are made for other distros) 7 | - **And** an [ourmachinery.com](https://ourmachinery.com/) account. [Sign up here!](https://ourmachinery.com/sign-up.html) 8 | 9 | On Linux, you also need to install the following packages for the runtime: 10 | 11 | ~~~bash 12 | sudo apt-get install libxcb-ewmh2 libxcb-cursor0 libxcb-xrm0 unzip 13 | ~~~ 14 | 15 | *This does not work on your distro*? No problem, visit our [Linux installation process across distributions guide](https://github.com/OurMachinery/themachinery-public/discussions/616). 16 | 17 | ## Getting up and running 18 | 19 | Quick steps to get up and running: 20 | 21 | 1. Download The Machinery at [https://ourmachinery.com/download.html](https://ourmachinery.com/download.html). 22 | 23 | 2. Sign up for an [ourmachinery.com](https://ourmachinery.com/) account [here](https://ourmachinery.com/sign-up.html). (It's free!) 24 | 25 | 3. Unzip the downloaded zip file to a location of your choosing. 26 | 27 | 4. Run `bin/the-machinery.exe` in the downloaded folder to start The Machinery. 28 | 29 | 5. Login with your [ourmachinery.com](https://ourmachinery.com/) account at the login screen and approve the EULA. 30 | 31 | 6. To find some samples to play with go to **Help > Download Sample Projects** in the main menu. 32 | 33 | 7. Pick one of the sample projects (for example **Physics**), click **Get** and then **Open**. 34 | 35 | 8. Play around with it, try some other samples and read the rest of this document to find out what 36 | else you can do with The Machinery. 37 | 38 | If you get errors that mention Vulkan or if you see weird rendering glitches, make sure to update 39 | your GPU drivers to the latest version. If that doesn't work, post an issue with our [issue 40 | tracker](https://github.com/OurMachinery/themachinery-public/issues) or ping us on [Discord](https://discord.gg/uJtkbVr) and we will help you. 41 | 42 | Related videos to these topics are: 43 | 44 | 45 | 46 | ## Source Code access 47 | 48 | You can make use of `tmbuild` (from the binary build) to download the engine (source code) and install all needed dependencies as well. This can be done via `tmbuild --install` in this case you may want to use `--github-token` as well and provide your token. Alternatively you can also manually clone the repo as you are used to from any other git repositories 49 | 50 | 51 | 52 | ### I signed up for source code but didn't get access. 53 | 54 | Make sure your GitHub account is correctly entered on the [Profile](https://ourmachinery.com/profile.html) page. It should be your account name, not your email. 55 | 56 | GitHub invites frequently end up in the Spam folder. Check there or go to the [repository](https://github.com/ourmachinery/themachinery) to see your invite. 57 | 58 | If you still have problems despite this, then contact us on ping@ourmachinery.com. -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/README.md: -------------------------------------------------------------------------------- 1 | # Introduction into C Programming 2 | 3 | This page will link to useful resources about the C Programming language. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | ## Reference 10 | - [C Reference](https://en.cppreference.com/w/c) 11 | 12 | ## Tutorials 13 | 14 | - [Tutorials Point: C Introduction](https://www.tutorialspoint.com/cprogramming/index.htm) 15 | - [Geeks for Geeks: Introduction to C](https://www.geeksforgeeks.org/c-language-set-1-introduction/) 16 | - [C Programming: Introduction](https://www.cprogramming.com/tutorial/c/lesson1.html) 17 | - [The C beginner Handbook](https://www.freecodecamp.org/news/the-c-beginners-handbook/) 18 | 19 | 20 | ## Videos 21 | 22 | - [C Programming for Beginners | What is C language | Tutorial Series](https://www.youtube.com/watch?v=wKoGImLA2KA&list=PLsyeobzWxl7oBxHp43xQTFrw9f1CDPR6C) 23 | - [C Programming Language - Intro to Computer Science - Harvard's CS50 (2018)](https://www.youtube.com/watch?v=ix5jPkxsr7M&list=PLWKjhJtqVAbmGw5fN5BQlwuug-8bDmabi) 24 | - [Modern C and What We Can Learn From It - Luca Sas [ ACCU 2021 ]](https://www.youtube.com/watch?v=QpAhX-gsHMs) 25 | 26 | 27 | ## The Machinery specials 28 | 29 | These are things that differ from std C practices. This is what you find in the sub chapters. -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/concurrency.md: -------------------------------------------------------------------------------- 1 | # Concurrency in Machinery 2 | 3 | In The Machinery we are making use of our [Fiber Job System](https://ourmachinery.com/post/fiber-based-job-system/) as well as of our Task System. We have a blog post that explains our fiber job system in its core ideas [Fiber based job system](https://ourmachinery.com/post/fiber-based-job-system/). Also for more details in how they are implemented see our source code or check the api docs: [Job System]({{doc}}/foundation/job_system.h.html) and [Task System]({{doc}}/foundation/task_system.h.html). This guide introduces you on how to use them and how you can syncronize your data. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | ## Syncronization Primitives 10 | 11 | TBA 12 | 13 | ## Task System 14 | 15 | TBA 16 | 17 | ## Job System 18 | 19 | TBA 20 | -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/hashmaps_and_set.md: -------------------------------------------------------------------------------- 1 | # Hashmap and set 2 | 3 | In The Machinery we make use our own hashmap that is implemented in the `hash.inl` file. Our Hashmap is the fundation for our Set implementation as well. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | ## Hashmap 10 | 11 | Example: 12 | 13 | ```c 14 | #include 15 | struct TM_HASH_T(key_t, value_t) hash = {.allocator = a}; 16 | 17 | tm_hash_add(&hash, key, val); 18 | value_t val = tm_hash_get(&hash, key); 19 | ``` 20 | 21 | The hashes in The Machinery map from an arbitrary 64-bit key type `K` (e.g. `uint64_t`, `T *`, `tm_tt_id_t`, `tm_entity_t`, ...) to an arbitrary value type `V`. 22 | 23 | Only 64-bit key types are supported. If your hash key is smaller, extend it to 64 bits. If your hash key is bigger (such as a string), pre-hash it to a 64-bit value and use *that* as your key. 24 | 25 | If you use a pre-hash, note that the hash table implementation here doesn't provide any protection against collisions in the *pre-hash*. Instead, we just rely on the fact that such collisions are statistically improbable. 26 | 27 | > **Note:** such collisions become a problem in the future, we might add support for 128-bit keys to reduce their probability further. 28 | 29 | The hash table uses two sentinel key values to mark unused and deleted keys in the hash table: `TM_HASH_UNUSED = 0xffffffffffffffff` and `TM_HASH_TOMBSTONE = 0xfffffffffffffffe`. Note that these values can't be used as keys for the hash table. If you are using a hash function to generate the key, we again rely on the statistical improbability that it would produce either of these values. (You could also modify your hash function so that these values are never produced.) 30 | 31 | ### Commonly hash types. 32 | 33 | Our implementation comes with some predefined commonly used hash types: 34 | 35 | | Name | Description | 36 | | -------------------- | ------------------------------------------------------------ | 37 | | `tm_hash64_t` | Maps from an `uint64_t` key to an `uint64_t` value. | 38 | | `tm_hash32_t` | Maps from an `uint64_t` key to a `uint32_t` value. | 39 | | `tm_hash64_float_t` | Maps from an `uint64_t` key to a `float` value. | 40 | | `tm_hash_id_to_id_t` | Maps from an [`tm_tt_id_t`](https://ourmachinery.com//apidoc/foundation/api_types.h.html#structtm_tt_id_t) key to a [`tm_tt_id_t`](https://ourmachinery.com//apidoc/foundation/api_types.h.html#structtm_tt_id_t) value. | 41 | 42 | ### How to iterate over the map? 43 | 44 | You make iterate over a hashmap: 45 | ```c 46 | for (uint64_t *k = lookup.keys; k != lookup.keys + lookup.num_buckets; ++k) { 47 | if (tm_hash_use_key(&lookup, k)){ 48 | //.. 49 | } 50 | } 51 | ``` 52 | 53 | ## Sets 54 | 55 | Example: 56 | 57 | ```c 58 | #include 59 | struct TM_SET_T(key_t) hash = {.allocator = a}; 60 | 61 | tm_set_add(&hash, key); 62 | if(tm_set_hash(&hash, key)) 63 | { 64 | // ... 65 | } 66 | ``` 67 | 68 | The set in The Machinery map from an arbitrary 64-bit key type `K` (e.g. `uint64_t`, `T *`, `tm_tt_id_t`, `tm_entity_t`, ...) to an arbitrary value type `V`. 69 | 70 | Only 64-bit key types are supported. If your set key is smaller, extend it to 64 bits. If your set key is bigger (such as a string), pre-hash it to a 64-bit value and use *that* as your key. 71 | 72 | ### Commonly set types. 73 | 74 | Our implementation comes with some predefined commonly used hash types: 75 | 76 | | Name | Description | 77 | | ------------------ | ------------------------------------------------------------ | 78 | | `tm_set_t` | Represents a set of `uint64_t` keys. | 79 | | `tm_set_id_t` | Represents a set of [`tm_tt_id_t`](https://ourmachinery.com//apidoc/foundation/api_types.h.html#structtm_tt_id_t) keys. | 80 | | `tm_set_strhash_t` | Represents a set of hashed strings. | 81 | 82 | ### How to iterate over the map? 83 | 84 | You make iterate over a set: 85 | 86 | ```c 87 | for (uint64_t *k = lookup.keys; k != lookup.keys + lookup.num_buckets; ++k) { 88 | if (tm_set_use_key(&lookup, k)){ 89 | //.. 90 | } 91 | } 92 | ``` -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/list_arrays_vector.md: -------------------------------------------------------------------------------- 1 | # Arrays, Vectors, Lists where is my `std::vector<>` or `List<>` 2 | 3 | **Table of Content** 4 | 5 | * {:toc} 6 | 7 | In the foundation we have a great header file or better inline header file the `foundation/carray.inl` which contains our solution for dynamic growing arrays, lists etc. When used you are responsible for its memory and have to free the used memory at the end! Do not worry, the API makes it quite easy. 8 | 9 | Let us create an Array of `tm_tt_id_t`. All we need to do is declare our variable as a pointer of `tm_tt_id_t`. 10 | 11 | ```c 12 | tm_tt_id_t* our_ids = 0; 13 | ``` 14 | 15 | After this we can for example push / add some data to our array: 16 | 17 | ```c 18 | tm_carray_push(our_ids,my_id,my_allocator); 19 | ``` 20 | 21 | Now the my_id will be stored in the our_ids and allocated with my_allocator! In the end when I do not need my array anymore, I can call: `tm_carray_free(our_ids,my_allocator)`, and my memory is freed! 22 | 23 | This doesn't look very pleasant when I am working with a lot of data that only needs to be a temporary list or something. For this case, you can use our temp allocator! Every `tm_carray_` macro has a `tm_carray_temp_` equivalent. 24 | 25 | > **Note:** It is also recommended to make use of `tm_carray_resize` or `tm_carray_temp_resize` if you know how many elements your array might have. This will reduce the actual allocations. 26 | 27 | Going back to our previous example: 28 | 29 | ```c 30 | TM_INIT_TEMP_ALLOCATOR(ta); 31 | tm_tt_id_t* all_objects = tm_the_truth_api->all_objects_of_type(tt, type, ta); 32 | // do some magic 33 | TM_SHUTDOWN_TEMP_ALLOCATOR(ta); 34 | ``` 35 | 36 | `tm_the_truth_api->all_objects_of_type` actually returns a `carray` and you can operate on it with the normal C array methods: e.g. `tm_carray_size()` or `tm_carray_end()`. Since it is allocated with the temp allocator you can forget about the allocation at the end as long as you call `TM_SHUTDOWN_TEMP_ALLOCATOR`. 37 | 38 | ### How to access an element? 39 | 40 | You can access a carray element normally like you would access it in a plain c array: 41 | 42 | ```c 43 | TM_INIT_TEMP_ALLOCATOR(ta); 44 | tm_tt_id_t* all_objects = tm_the_truth_api->all_objects_of_type(tt, type, ta); 45 | if(all_objects[8].u64 == other_objects[8].u64){ 46 | // what happens now? 47 | } 48 | TM_SHUTDOWN_TEMP_ALLOCATOR(ta); 49 | ``` 50 | 51 | ### Iterate over them 52 | 53 | You can iterate over the carray like you would iterate over a normal array: 54 | 55 | ```c 56 | TM_INIT_TEMP_ALLOCATOR(ta); 57 | tm_tt_id_t* all_objects = tm_the_truth_api->all_objects_of_type(tt, type, ta); 58 | for(uint64_t i = 0;i < tm_carray_size(all_objects);++i){ 59 | TM_LOG("%llu",all_objects[i].u64);// we could also use TM_LOG("%p{tm_tt_id_t}",&all_objects[i]); 60 | } 61 | TM_SHUTDOWN_TEMP_ALLOCATOR(ta); 62 | ``` 63 | 64 | An alternative approach is a more for each like approach: 65 | 66 | ```c 67 | TM_INIT_TEMP_ALLOCATOR(ta); 68 | tm_tt_id_t* all_objects = tm_the_truth_api->all_objects_of_type(tt, type, ta); 69 | for(tm_tt_id* id = all_objects;id != tm_carray_end(all_objects);++id){ 70 | TM_LOG("%llu",id->u64);// we could also use TM_LOG("%p{tm_tt_id_t}",id); 71 | } 72 | TM_SHUTDOWN_TEMP_ALLOCATOR(ta); 73 | ``` 74 | 75 | -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/other.md: -------------------------------------------------------------------------------- 1 | # Types: void* and struct padding 2 | -------------------------------------------------------------------------------- /src/getting_started/introduction_to_c/strings.md: -------------------------------------------------------------------------------- 1 | # String processing 2 | -------------------------------------------------------------------------------- /src/getting_started/logging_in.md: -------------------------------------------------------------------------------- 1 | ## Sign in 2 | 3 | When you first run `the-machinery.exe`, you will encounter a login screen: 4 | 5 | ![Login screen.](https://www.dropbox.com/s/07rcwx7b1pggnxe/sign-in.png?raw=1) 6 | 7 | To use the editor, you must log in with an Our Machinery account. If you haven't done so already, press the *Sign Up* button to create an account, or go directly to [https://ourmachinery.com/sign-up.html](https://ourmachinery.com/sign-up.html). 8 | 9 | In addition, you also need to agree to our [EULA](https://www.ourmachinery.com/eula.html). 10 | -------------------------------------------------------------------------------- /src/getting_started/new_project.md: -------------------------------------------------------------------------------- 1 | # Getting Started with a New Project 2 | 3 | This walkthrough shows how to create a new project. It will also show you what comes by default with the Engine. 4 | 5 | This part will cover the following topics: 6 | 7 | - Project Pipeline 8 | - What is the difference between a directory project and a database project? 9 | - What is a Scene in The Machinery? 10 | - What comes by default with a project? 11 | 12 | 13 | **Table of Content** 14 | 15 | * {:toc} 16 | 17 | # About Scenes 18 | 19 | In The Machinery, we do not have a concept of scenes in the traditional sense. All we have are Entities. Therefore any Entity can function as a scene. All you need is to add child entities to a parent Entity. The Editor will remember the last opened Entity. 20 | When publishing a Game, the Engine will ask you to select your "world" entity. You can decide to choose any of your entities as "world" Entity. 21 | 22 | > For more information on publishing, check [here]({{base_url}}editing_workflows/publish.html). 23 | 24 | # New Project 25 | 26 | After the Machinery has been launched for the first time and the login was successful, the Engine will automatically show you a new empty project. If you do not have an account, you can create an account for free [here](https://ourmachinery.com/sign-up.html), or if you had any trouble, don't hesitate to get in touch with us [here](mailto:ping@ourmachinery.com). 27 | 28 | At any other point in time, you can create a new project via **Files → New Project.** 29 | 30 | A new project is not empty. It comes with the so-called "**Core**," a collection of valuable assets. They allow you to start your project quickly. Besides the *Core*, the project will also contain a default World Entity, functioning as your current scene. By default, the world entity includes 2 child entities: *light and post_process*. Those child entities are instances of prototypes. 31 | 32 | > A prototype in The Machinery is an entity that has been saved as an Asset. Prototypes are indicated by yellow text in the Entity Tree View. 33 | > 34 | > For more information about Prototypes, click [here]({{base_url}}editing_workflows/prototype_workflow/index.html). 35 | 36 | 37 | ![the content of the world entity](https://paper-attachments.dropbox.com/s_09462F237550F87F4C86951FAA779F713337E632E917FE6E6B8E3406BD58F125_1615455893513_image.png) 38 | 39 | 40 | ### The Core 41 | Let us discuss the Core a bit. As mentioned before, the Core contains a couple of useful utilities. They are illustrating the core concepts of the Engine, and they are a great starting point. They can be found in the Asset browser under the core folder: 42 | 43 | ![](https://paper-attachments.dropbox.com/s_09462F237550F87F4C86951FAA779F713337E632E917FE6E6B8E3406BD58F125_1615456601483_image.png) 44 | 45 | 46 | A content overview of the core folder and its subfolders may looks like this: 47 | 48 | - A light entity 49 | 50 | - A camera entity 51 | 52 | - A post-processing stack entity (named post-process in the world entity) 53 | 54 | - A default light environment entity 55 | 56 | - A post-processing volume entity 57 | 58 | - A default world entity (the blueprint of the world entity) 59 | 60 | - A bunch of helpful geometry entities. They are in the geometry folder. 61 | 62 | - A sphere entity 63 | - A box entity 64 | - A plane entity 65 | - as well as their geometry material 66 | 67 | - A bunch of default creation graphs is in the folder creation_graphs 68 | 69 | - import-image 70 | - DCC-mesh 71 | - editor-icon 72 | - drop-image 73 | - DCC-material 74 | - DCC-image 75 | 76 | 77 | 78 | ## How to add some life to your project 79 | 80 | All gameplay can be written in C or a C in any binding language such as C++ or Zig. You can also create gameplay code via the Entity Graph. The Entity Graph would live inside of a Graph Component. You can add that to an Entity. 81 | 82 | You can find more information about gameplay coding in the ["Gameplay Coding" Section]({{base_url}}gameplay_coding/index.html) 83 | 84 | 85 | 86 | ## Project Structure Recommendation 87 | 88 | It is recommended to separate your gameplay source code, plugin code from the actual project and store them in a separate folder. 89 | 90 | ``` 91 | my_project/game_project // the directory project 92 | my_project/game_plugins // the main folder for all your gameplay code, plugins 93 | ``` 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /src/getting_started/project_setup.md: -------------------------------------------------------------------------------- 1 | # Project Setup 2 | 3 | In The Machinery, we have two kinds of projects: A database project and a directory project. It is possible to save a database project as a directory project and vice versa. 4 | 5 | > **Note:** When saving a Database project as a Directory project or vice versa, be aware that these are two different projects. Hence changes to one will not apply to the other. 6 | 7 | ## The Directory Project 8 | 9 | A directory project saves all your assets, etc., in a specified project folder. The assets that make up the project are saved as combination of JSON files and binary buffers. This file format is better suited for source control. 10 | 11 | ![view of a directory project in the Windows explorer](https://www.dropbox.com/s/7xqwlu6yi6y35nz/tm_guide_directory_project.png?raw=1) 12 | 13 | ## The Asset database Project 14 | 15 | In contract to the Directory project, the database project results in one file rather than multiple files. It has the file ending `.the_machinery_db`. This database will contain all your assets. It loads faster. It is the file format used by the *Runner*, the stand-alone application that is used to run games made within The Machinery. 16 | 17 | ![database project in the file explorer](https://www.dropbox.com/s/kjmrx89my0olh6z/tm_guide_db_project.png?raw=1) 18 | 19 | ## Project Management 20 | 21 | **Can I directly add Assets to my project from the File Explorer of my OS?** 22 | 23 | **No**, the editor will not import assets directly added to the project folder via your OS File Explorer. However you can modify The Machinery files (in a directory project) during runtime or before. If you do this the Engine will warn you. 24 | 25 | > Changes to the project on disk where detected: [Import] [Ignore] 26 | 27 | More information on this topic [here](https://github.com/OurMachinery/themachinery-public/issues/435). 28 | 29 | You handle the main project management steps through the **File Menu.** Such as Create and Save. By default, (1) The Machinery will save your project as a directory project. However you can save your current project as an Asset Database (2). 30 | 31 | ![](https://www.dropbox.com/s/qosmerpjea1agss/tm_guide_saving_project.png?raw=1) 32 | 33 | ## Possible folder structure for a project 34 | 35 | The following project shows a possible folder structure of a game project. **This is not a recommendation just a suggestion**. At the end it depends on your needs and your workflows how your projects should be structured. 36 | 37 | ![](https://www.dropbox.com/s/sbdsy1k5wjay89c/tm_guide_possible_folder_structure.png?raw=1) 38 | 39 | 1. `game_project` contains a The Machinery Directory Project 40 | 2. `plugins` contains the dll of your plugins (should not be checked in into source control) 41 | 3. `raw_assets` may contain the raw assets your DCC tool needs to process. Your the Machinery project can point here and you maybe able to just reimport things from there if needed 42 | 4. `src` contains the source code of your plugins. They can be in multiple sub folder depending on your liking and need. 43 | 44 | **Example `src` folder** 45 | 46 | ![](https://www.dropbox.com/s/l1429g7p5xx8kj2/tm_guide_possible_subfolder.png?raw=1) 47 | 48 | In here we have one single `premake` file and a single `libs.json` as well as the `libs` folder. This allows you to run `tmbuild` just in this folder and all plugins or the ones you want to build can be built at once. Besides it will generate one solution for Visual Studio. In this example all plugins will copy their `.dll/so` files into the `../plugins` folder. 49 | 50 | 51 | 52 | A possible `.gitignore` 53 | 54 | ``` 55 | plugins/* 56 | src/libs/* 57 | ``` 58 | 59 | as well as the default Visual Studio, Visual Studio Code and C/C++ gitignore content. 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/getting_started/sample-projects.md: -------------------------------------------------------------------------------- 1 | # Sample Projects 2 | 3 | You can download any sample project you like from our website: [OurMachinery: Samples](https://ourmachinery.com/samples.html). Alternatively you find them under **Help > Download Sample Projects** in the main menu. After you have downloaded them you can open them via the *Download Tab* or directly from the hard drive. 4 | 5 | A few sample projects are coming by default with the Engine, you find them in the root folder under `samples/`. If you are interested in how our tools work you can look their source code up in the `code/` folder. 6 | -------------------------------------------------------------------------------- /src/graphics/README.md: -------------------------------------------------------------------------------- 1 | # Graphics 2 | 3 | ![](https://ourmachinery.com/images/eap.jpg) 4 | 5 | ## Modern rendering architecture 6 | 7 | The renderer has been designed to take full advantage of modern explicit graphic APIs like Vulkan. You can reason explicitly about advanced setups such as multiple GPUs and GPU execution queues. Similar to the rest of the engine, the built-in rendering pipeline is easy to tweak and extend. 8 | 9 | ## Supported graphics backends 10 | 11 | - Vulkan 1.2 12 | - Nil 13 | 14 | -------------------------------------------------------------------------------- /src/graphics/default_render_pipeline.md: -------------------------------------------------------------------------------- 1 | # 2 | 3 | ![](https://www.dropbox.com/s/61buexu1hw0pvms/tm_default_render_pipeline.png?raw=1) -------------------------------------------------------------------------------- /src/graphics/lighting/README.md: -------------------------------------------------------------------------------- 1 | # Lighting 2 | 3 | The Machinery’s default render pipeline provides a basic lighting stack for common lighting effects. All of these are handled through components and are capable of using the volume component to localize their effect to a spatial domain. This section will provide some clarity on how to best use these effects. 4 | 5 | Currently we support the following lighting effects: 6 | - [Ambient Occlusion]({{base_url}}/graphics/lighting/ambient_occlusion.html) -------------------------------------------------------------------------------- /src/graphics/lighting/ambient_occlusion.md: -------------------------------------------------------------------------------- 1 | # Ambient Occlusion 2 | 3 | Ambient Occlusion is an effect as part of global illumination that approximates the attenuation of light due to occlusion. 4 | 5 | ![SSAO](https://www.dropbox.com/s/9hemw29ib130jf3/tm_tut_ssao.png?raw=1) 6 | 7 | The easiest way to get AO in your scene is by adding SSAO component which is a method that calculates ambient occlusion in screen space using the depth and normal buffer from the GBuffer rendering pass. 8 | 9 | | **Property** | **Description** | 10 | | :-- | :----- | 11 | | Radius | Defines the sample radius in world space units. Larger radius needs more step count to be more correct but higher step count can hurt performance. Having larger radius also makes cutoffs on the edges of the screen more visible because screen space effects don't have scene information outside of screen. | 12 | | |  ![SSAO radius compare](https://www.dropbox.com/s/pcekns9g3qbzh5d/tm_tut_ssao_radius_comp.png?raw=1) *SSAO with radius set to 1(Left)   SSAO with radius set to 5(Right)*| 13 | | Power | Controls the strength of the darkening effect that, increases the contrast.| 14 | | |  ![SSAO power compare](https://www.dropbox.com/s/ktp9l66mmqptrrk/tm_tut_ssao_power_comp.png?raw=1) *SSAO with power set to 1.5(Left)   SSAO with power set to 3.0(Right)* | 15 | | Bias | Depth buffer precision in the distance and high-frequency details in normals can cause some artifacts and noise. This parameter allows you to tweak it. But higher value will reduce details. | 16 | | |  ![SSAO power compare](https://www.dropbox.com/s/m1h2qic1g7fpwh0/tm_tut_ssao_bias_comp.png?raw=1) *SSAO with bias set to 0.0(Left)   SSAO with bias set to 0.1(Right)* | 17 | | Step Count | The number of depth samples for each sample direction. This property has direct corelation with performance. Keeping it in 4-6 range will result optimal performance/quality ratio. | 18 | 19 | ## Technical Details 20 | 21 | The SSAO implementation is based on the slides from [Practical Real-Time Strategies for Accurate Indirect Occlusion](https://blog.selfshadow.com/publications/s2016-shading-course/#course_content) presented at Siggraph 2016. It consist of 4 passes: 22 | - **Half Screen Trace Pass:** Calculates the horizon for a sample direction and the corresponding occlusion with 4x4 noise. 23 | - **Half Screen Spatial Denoiser:** Resolves that 4x4 noise with a bilateral 4x4 box blur. 24 | - **Half Screen Temporal Denoiser:** Temporally stables the result from spatial blur. Increases the sample count and reduces the flickering. 25 | - **Full Screen Bilateral Upscale:** Depth aware upscale pass that brings the denoised AO target to full resolution. 26 | -------------------------------------------------------------------------------- /src/graphics/mesh_materials.md: -------------------------------------------------------------------------------- 1 | {{#include ../creation_graphs/concept.md}} 2 | -------------------------------------------------------------------------------- /src/graphics/post_processing/README.md: -------------------------------------------------------------------------------- 1 | # Post Processing 2 | 3 | The Machinery’s default render pipeline provides a basic post processing stack for common effects. All of these are handled through components and are capable of using the volume component to localize their effect to a spatial domain. This section will provide some clarity on how to best use these effects. 4 | 5 | Currently we support the following post-processing effects: 6 | - [Anti-Aliasing]({{base_url}}/graphics/post_processing/aa.html) 7 | - [Exposure]({{base_url}}/graphics/post_processing/exposure.html) 8 | - [Bloom]({{base_url}}/graphics/post_processing/bloom.html) 9 | - [Color grading]({{base_url}}/graphics/post_processing/color_grading.html) -------------------------------------------------------------------------------- /src/graphics/post_processing/aa.md: -------------------------------------------------------------------------------- 1 | # Adjusting Anti-Aliasing 2 | 3 | Anti-Aliasing (AA) refers to various techniques for smoothing aliased, or jagged edges when dealing with a finite number of samples, like a monitor. The Machinery supports Temporal Anti-Aliasing (TAA) as a post-processing effect. Multisample Anti-Aliasing (MSAA) support is planned on a per image level, but is currently not available to all render backends. 4 | 5 | ![No TAA (left) vs TAA (right)](https://www.dropbox.com/s/98wyr2w26dbe8r6/tm_tut_aa.png?raw=1) 6 | 7 | ![TAA Settings](https://www.dropbox.com/s/8196q7vpn5bujx8/tm_tut_aa_settings.png?raw=1) -------------------------------------------------------------------------------- /src/graphics/post_processing/bloom.md: -------------------------------------------------------------------------------- 1 | # Bloom 2 | 3 | Bloom (or glow) is an effect for real world lenses that produces fringes of light that extend from the borders of bright areas in the scene. It is produced by diffraction patterns of light sources through a lens aperture. This particularly affects lights sources and emissive materials. 4 | In The Machinery this is implemented as multiple Gaussian blurs that only affect the bright areas on the scene. 5 | 6 | ![Bloom On (left) and Off (right)](https://www.dropbox.com/s/zqx30bzzt86rqyo/tm_tut_bloom_on_off.png?raw=1) 7 | 8 | | **Property** | **Description** | 9 | | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | 10 | | Threshold | The luminance threshold for bloom to start considering a sample. This is roughly measured in Lux. | 11 | | Falloff | Defines the size of the bloom fringes. More falloff means larger fringes. | 12 | | Tint | A chromatic tint mask that will be applied to the bloom effect. Setting this to black will render the bloom effect useless without any performance benefit. | -------------------------------------------------------------------------------- /src/graphics/post_processing/color_grading.md: -------------------------------------------------------------------------------- 1 | # Color Grading 2 | 3 | The Machinery supports industry standard methods for color grading for HDR colors. Currently, there is no support for custom tone mappers: 4 | 5 | ![Controls](https://www.dropbox.com/s/f51xt0yd696w3jv/tm_tut_color_grading_lgg_sop.png?raw=1) 6 | 7 | The [Color Grading]({{docs}}/plugins/default_render_pipe/post_processing/color_grading_component.h.html#color_grading_component.h) component allows you to use either Lift/Gamma/Gain controls or ASC-CDL controls. Regardless of the method used, the shader will apply a single ASC-CDL transform per channel. The resulting transform is visualized using the graph. Color grading is applied just before the tone mapper in ACEScg space. 8 | 9 | ![](https://www.dropbox.com/s/v8xm2u9ln0dy065/tm_tut_color_grading_flow.png?raw=1) 10 | 11 | ![](https://www.dropbox.com/s/9080y9197sr1p5v/tm_tut_color_grading_tools.png?raw=1) 12 | 13 | The Color Scopes Tab can be used to visualize the color spread in your scene. This might aid in color grading. -------------------------------------------------------------------------------- /src/graphics/shaders.md: -------------------------------------------------------------------------------- 1 | # Shaders 2 | 3 | The Creation Graph provides an artist-friendly way to create custom shaders by wiring together nodes into a shader network. Each node in the graph represents a snippet of HLSL code that gets combined by the shader system plugin into full HLSL programs. It can sometimes be nice to work directly with HLSL code for more advanced shaders, either by exposing new helper nodes to the Creation Graph or by directly writing a complete shader program in HLSL. This is typically done by adding new `.tmsl` files (where `tmsl` stands for `The Machinery Shading Language`) that The Machinery loads on boot up. 4 | 5 | A `.tmsl` file is essentially a data-driven JSON front-end for creating and populating a `tm_shader_declaration_o` structure which is the main building block that the compiler in shader system plugin operates on. While a `tm_shader_declaration_o` can contain anything needed to compile a complete shader (all needed shader stages, any states and input/output it needs, etc), it is more common that they contain only fragments of and multiple `tm_shader_declaration_o` are combined into the final shader source that gets compiled into a `tm_shader_o` that can be used when rendering a draw call (or dispatching a compute job). 6 | 7 | 8 | 9 | > **Note:** You can find all built-in shaders in the folder: `./bin/data/shaders` shipped with your engine version. (For source access: `./the_machinery/shaders`) 10 | 11 | 12 | 13 | Inserting the `creation_graph` block in the `.tmsl` file will get exposed as a node in the Creation Graph. Nodes exposed to the Creation Graph can either be *function* nodes (see: `data/shaders/nodes/`) or *output* nodes (see: `data/shaders/output_nodes/`). A *function* node won't compile into anything by itself unless it's connected to an *output* node responsible for declaring the actual shader stages and evaluating the branches of connected *function* nodes. 14 | 15 | 16 | 17 | > **Note:** More information about creating creation graph nodes you can find in the Creation Graph Section: 18 | > 19 | > - [Node Types]({{base_url}}/creation_graphs/node_types.html) 20 | > 21 | > - [Shader system interaction]({{base_url}}/creation_graphs/shader_system.html) 22 | > 23 | > - [Create custom GPU node Tutorial]({{base_url}}/tutorials/creation_graph/custom_gpu_nodes.html) 24 | 25 | 26 | 27 | Typically these are function nodes (see `data/shaders/nodes`) that won't compile into anything without getting connected to an "output" node. We ship with a few built-in output nodes (see `data/shaders/output_nodes`) responsible for declaring the actual shader stages and glue everything together. 28 | 29 | > **Note:** For more details on the Shader Language itself, please check the [Shader Reference](https://ourmachinery.com/apidoc/doc/shader_system_reference.md.html) or the Chapter [The Machinery Shading Language]({{base_url}}graphics/the_machinery_shading_language.html). 30 | 31 | The whole Shader System is explained in more detail within these posts: 32 | 33 | - [The Machinery Shader System (part 1)](https://ourmachinery.com/post/the-machinery-shader-system-part-1/) 34 | - [The Machinery Shader System (part 2)](https://ourmachinery.com/post/the-machinery-shader-system-part-2/) 35 | - [The Machinery Shader System (part 3)](https://ourmachinery.com/post/the-machinery-shader-system-part-3/) 36 | - [Efficient binding of shader resources](https://ourmachinery.com/post/efficient-binding-of-shader-resources/) 37 | 38 | 39 | 40 | ## Custom shaders how? 41 | 42 | If you intend to write custom shaders you can. All your custom shaders need to be placed under the `bin\data\shaders` of the engine. They will be automatically compiled (if needed) on boot up of the Editor. For help with how to write a custom shader please follow the [`The Machinery Shading Language Guide`]({{base_url}}/graphics/the_machinery_shading_language.html) -------------------------------------------------------------------------------- /src/graphics/the_machinery_shading_language.md: -------------------------------------------------------------------------------- 1 | # The Machinery Shader Language 2 | 3 | Shaders in The Machinery are defined using The Machinery Shader Language (`tmsl`). Traditionally shaders (like those written in `glsl` or `hlsl`) only contain the shader code itself and some I/O definitions. The Machinery (like other engines) stores not only the shader code, but also the pipeline state in its shader files. Additionally The Machinery allows shaders to define variations and systems that allow for more complex shader generation and combinations. For a complete list of what can be in a `tmsl` file see the [Shader System Reference](https://ourmachinery.com/apidoc/doc/shader_system_reference.md.html). For an in depth look at the design goals of these shader files see [The Machinery Shader System](https://ourmachinery.com/post/the-machinery-shader-system-part-1/) blog posts. 4 | 5 | A shader file can be divided into three distinct sections: 6 | 7 | - Code blocks, these define [HLSL](https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl) code blocks that contain the main shader code. 8 | - Pipeline state blocks, these define the Pipeline State Objects (PSO) or shader environment required for the code to run. 9 | - Compilation blocks, these define meta information about how the shader should be compiled. This also allows for multiple variations of shaders, for instance one with multi-sampling enabled and one with multi-sampling disabled. 10 | 11 | Let’s have a look at a `Hello Triangle` shader for The Machinery. 12 | 13 | ```json 14 | imports: [ 15 | { name: "color" type: "float3" } 16 | ] 17 | 18 | vertex_shader: { 19 | import_system_semantics : [ "vertex_id" ] 20 | 21 | code: [[ 22 | const float2 vertices[] = { 23 | float2(-0.7f, 0.7f), 24 | float2(0.7f, 0.7f), 25 | float2(0.0f, -0.7f) 26 | }; 27 | 28 | output.position = float4(vertices[vertex_id], 0.0f, 1.0f); 29 | return output; 30 | ]] 31 | } 32 | 33 | pixel_shader: { 34 | code: [[ 35 | output.color = load_color(); 36 | return output; 37 | ]] 38 | } 39 | 40 | compile: {} 41 | ``` 42 | 43 | In this example we have some shader code, no explicit pipeline state, and an empty compile block. The first thing to note is that `tmsl` files use a JSON like format. The main sections of code are the `vertex_shader` and the `pixel_shader` blocks. Within these are `code` blocks which specify the HLSL code that needs to run at the relative pipeline stage. In this example we create a screen-space triangle from three constant vertices and give it a color passed on as an input. 44 | 45 | If we want to pass anything to a shader we need to define it in the `imports` block. Anything defined in here will be accessible though `load_#` or `get_#` functions. See the [Shader System Reference](https://ourmachinery.com/apidoc/doc/shader_system_reference.md.html) for more information. 46 | 47 | We also need to define a `compile` or `system` block in order for our shader to be compiled. If neither block is defined then the shader is assumed to be a library type shader which can be included into other shaders. 48 | 49 | > **Note:** You can find all built-in shaders in the folder: `./bin/data/shaders/` in the shipped engine (for source code access this is: `./the_machinery/shaders/`). 50 | 51 | 52 | ## Procedural shaders 53 | 54 | Note that shaders don’t have to be written and compiled in this way. You can generate shaders directly from code using the `tm_shader_repository_api`. You can create a new shader declaration by calling `create_shader_declaration()`, populate it with your custom code by using the `tm_shader_declaration_api`, and compile it using `create_from_declaration()`. Any `tmsl` file will go through the same pipeline. 55 | 56 | 57 | > **Note:** Shader are also used to create GPU nodes for the Creation Graph, see Creation Graph: [Shader System Interaction]({{base_url}}/creation_graphs/shader_system.html) for more information. 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/graphics/tmsl_vs.md: -------------------------------------------------------------------------------- 1 | # The Machinery Shader Language [Visual Studio](https://visualstudio.microsoft.com/) Extension 2 | This [Visual Studio](https://visualstudio.microsoft.com/) extension adds The Machinery's `.tmsl` language support: 3 | - Syntax highlighting 4 | - Snippets 5 | 6 | ![image](https://user-images.githubusercontent.com/70658773/116350723-b1b0a480-a7f2-11eb-90d5-226099b34e90.png) 7 | 8 | ## Installation 9 | 10 | Open and download the extension from [VS Marketplace](https://marketplace.visualstudio.com/items?itemName=OurMachinery.tmShaderLang) and use it in VS Studio. 11 | 12 | > VS Code will follow at some point. -------------------------------------------------------------------------------- /src/licenses.md: -------------------------------------------------------------------------------- 1 | ## License 2 | 3 | We provide three different liceneses: 4 | 5 | - The **Indie Free** license is completely free for indie developers and includes all of The 6 | Machinery, except for the source code. It does come with full SDK to make new plugins as well as some sample plugins and the source code for the high-level parts of our rendering pipeline. 7 | 8 | - The **Indie Pro** license is the same as Indie Free, but also includes the full source code of the 9 | engine and all associated tools. Price: $100 / user / year. 10 | 11 | - The **Business** version is aimed towards larger businesses. Feature wise it is the same as Indie Pro, but comes with prioritized support. Price: $900 / user / year. 12 | 13 | The definition of "larger business" above is any company with a yearly revenue exceeding $100K, in which case you are not eligible to buying the Indie Pro license. 14 | 15 | All of the licenses allow for full royalty-free use of The Machinery. You can build and sell commercial games, tools, applications, and plugins. For more details, see our [pricing page](http://www.ourmachinery.com/pricing.html). 16 | 17 | When you download The Machinery, you will be on the Indie Free license. If you do not fall in the "indie" category, you can still use this license to evaluate The Machinery, but you need to buy a business license to put it into production. 18 | 19 | ## 2021 Early Adopter Program FAQ 20 | 21 | > I bought an early adopters license, will I continue to pay the discounted price when my subscription renews? 22 | 23 | Yes, as long as you don't cancel your subscription, you will continue to pay the discounted price for the next 5 years. 24 | -------------------------------------------------------------------------------- /src/qa_pipeline/README.md: -------------------------------------------------------------------------------- 1 | # QA Pipeline 2 | 3 | The Machinery comes with some built-in tools to support you in building games. 4 | 5 | - [Unit Test Framework]({{docs}}foundation/unit_test.h.html#unit_test.h) 6 | - [Integration Test Framework]({{docs}}foundation/integration_test.h.html#integration_test.h) 7 | - [Profiler and profiling framework]({{docs}}foundation/profiler.h.html#profiler.h) 8 | - [Memory leak Detection]({{docs}}foundation/memory_tracker.h.html#memory_tracker.h) 9 | -------------------------------------------------------------------------------- /src/qa_pipeline/memory.md: -------------------------------------------------------------------------------- 1 | # Memory Usage Tab 2 | 3 | The Machinery has a built-in Leak detection when one is using the provided allocators. Besides they all will log the used memory in the Memory Usage tab! 4 | 5 | - [Memory leak Detection]({{docs}}foundation/memory_tracker.h.html#memory_tracker.h) 6 | 7 | The memory tab will display all memory consumed via any allocator. Temporary allocators will be listed as well. Besides the memory from the CPU allocators, you can also inspect device memory used and the memory consumed by your assets. 8 | 9 | ![](https://paper-attachments.dropbox.com/s_5086E710AFB88B222C81207791AF7092731DB9D2900AFABEA044A0AC0B80DFFB_1625603084539_image.png) 10 | -------------------------------------------------------------------------------- /src/qa_pipeline/profiler.md: -------------------------------------------------------------------------------- 1 | 2 | # Profiler Tab 3 | 4 | The profiler tab will display all scopes that have been added to the profiler API. With the tab, you can record for a few moments all scopes and then afterward analyze them. 5 | 6 | ![](https://paper-attachments.dropbox.com/s_5086E710AFB88B222C81207791AF7092731DB9D2900AFABEA044A0AC0B80DFFB_1625602954215_image.png) 7 | 8 | You can use the profiler API defined in the [foundation/profiler]({{docs}}foundation/profiler.h.html#profiler.h).h. in your own projects. 9 | After you have loaded the [`tm_profiler_api`]({{docs}}foundation/profiler.h.html#structtm_profiler_api) in your plugin load function. 10 | 11 | | Profiler Macros | 12 | | ------------------------------------------------------------ | 13 | | **[TM_PROFILER_BEGIN_FUNC_SCOPE()]({{docs}}foundation/profiler.h.html#tm_profiler_begin_func_scope()) / [TM_PROFILER_END_FUNC_SCOPE()]({{docs}}foundation/profiler.h.html#tm_profiler_end_func_scope())** | 14 | | Starts a profiling scope for the current function. The scope in the profiler will have this name. | 15 | | **[TM_PROFILER_BEGIN_LOCAL_SCOPE(tag)]({{docs}}foundation/profiler.h.html#tm_profiler_begin_local_scope()) / [TM_PROFILER_END_LOCAL_SCOPE(tag)]({{docs}}foundation/profiler.h.html#tm_profiler_end_local_scope())** | 16 | | The call to this macro starts a local profiler scope. The scope is tagged with the naked word tag (it gets stringified by the macro). Use a local profiler scope if you need to profile parts of a function. | 17 | 18 | *Example:* 19 | 20 | ```c 21 | void my_function({{base_url}}*some arguments*/){ 22 | TM_PROFILER_BEGIN_FUNC_SCOPE() 23 | // .. some code 24 | TM_PROFILER_END_FUNC_SCOPE() 25 | } 26 | ``` 27 | -------------------------------------------------------------------------------- /src/qa_pipeline/statistics.md: -------------------------------------------------------------------------------- 1 | # Statistic Tab 2 | 3 | Allows you to visualize different statistics from different sources. 4 | 5 | ![](https://paper-attachments.dropbox.com/s_5086E710AFB88B222C81207791AF7092731DB9D2900AFABEA044A0AC0B80DFFB_1625603204224_image.png) 6 | 7 | 8 | The Statistic tab consists of a Property View in which you can define your desired method of display and source. You can choose between Table, Line, or no visualization method. As sources, the engine will offer you any of the profiler scopes. 9 | 10 | ![](https://paper-attachments.dropbox.com/s_5086E710AFB88B222C81207791AF7092731DB9D2900AFABEA044A0AC0B80DFFB_1625604230068_image.png) 11 | 12 | ## Statistics Overlay 13 | 14 | During the simulation in the simulate tab you have the ability to open different statistic overlays. 15 | 16 | ![https://www.dropbox.com/s/cmk3u9lt4d8l3n0/tm_guide_statistics_in_simulate.png?dl=1](https://www.dropbox.com/s/cmk3u9lt4d8l3n0/tm_guide_statistics_in_simulate.png?raw=1) 17 | 18 | -------------------------------------------------------------------------------- /src/the_editor/README.md: -------------------------------------------------------------------------------- 1 | # The Editor 2 | 3 | After opening the Engine, you should see the Editor's interface with menus along the top of the interface, and the basic tabs opened. The following image will show you the default engine layout. 4 | Here's a brief description of what you can see: 5 | 6 | ![](https://www.dropbox.com/s/67sdkq7sxnkbkou/tm_editor.png?raw=1) 7 | 8 | 1. The **Main Menu**: It allows you to navigate through the Engine, such as opening new tabs or import assets 9 | 2. The **Entity Tree** shows a tree view of the entity you are editing. It shows the entity's components and child entities. You start editing an entity by double-clicking it in the asset browser. 10 | 3. The **Scene** shows an editable graphic view of the edited entity. You can manipulate components and child entities by selecting them. Use the *Move*, *Rotate*, and *Scale* gizmos for your desired action. 11 | 4. The **Simulate current scene** button will open the **Simulate** tab that lets you "run" or "simulate" a scene. 12 | 5. The **Properties** tab shows the properties of the currently selected object in the Scene. You can modify the properties by editing them in the properties window. 13 | 6. The **Console** tab shows diagnostic messages from the application. 14 | 7. The **Asset Browser** shows all the assets in the project and enables you to manage them. 15 | 8. The **Preview** shows a preview of the currently selected asset in the asset browser. 16 | 17 | The Editor is a collection of editing *Tabs*, each with its specific purpose. You can drag tabs around to rearrange them. When you drag them out of the window, a new window opens. Use the *View* menu to open new tabs. 18 | 19 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625426655184_image.png) 20 | 21 | 22 | Note that you can have multiple tabs of the same type. For example, you can open various *Asset Browser* tabs to drag assets between them easily. Tabs docked in the same window work together. Therefore if you dock a *Preview* tab in the same window as an *Asset Browser*, it will show a preview of the selected asset in that browser. You can create multiple windows to view numerous assets simultaneously: 23 | 24 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625427376387_image.png) 25 | 26 | 27 | **Editor layouts** 28 | 29 | You can rearrange the Editor layouts by dragging tabs around in the Editor. The best structure for the Editor depends on what you are doing and your personal preferences. You can save layouts via the Window Menu. It is also possible to restore your layout to the default one or load a custom-defined one in this menu. 30 | -------------------------------------------------------------------------------- /src/the_editor/customizations.md: -------------------------------------------------------------------------------- 1 | # Interface Customizations 2 | 3 | In this guide, you will learn about how to customize the Engine's interface. 4 | 5 | - Change a theme 6 | - Export/Import a theme 7 | - Change the window scale. 8 | - Add layouts. 9 | - Modify the Global Grid settings. 10 | 11 | ## Change Theme 12 | 13 | Sometimes we do not like the default theme or, based on reasons such as color blindness, and we cannot use the default theme. In the Machinery, you can change the default theme via **Window -> Theme**. You will find a list of themes the user can select and use. 14 | 15 | ![](https://www.dropbox.com/s/yt180qozhyrw2zc/tm_guide_theme_picker.png?raw=1) 16 | 17 | The Engine comes by default with some base themes you can build your themes on top of: 18 | 19 | | Theme | 20 | | ------------------- | 21 | | Dark | 22 | | Light | 23 | | High Contrast Dark | 24 | | High Contrast Light | 25 | 26 | ## Custom Theme 27 | 28 | If you like to customize the default themes or create a new theme, click on the "**New Theme"** menu in the same menu as the theme selection. After clicking this, the current Theme will be used as your base, and the Theme Editor Tab opens. 29 | 30 | ![](https://www.dropbox.com/s/imcy0y9wgxh252k/tm_guide_theme_create.png?raw=1) 31 | 32 | If you do not like the base, you can choose a different theme as a base. 33 | 34 | ![change base of theme](https://www.dropbox.com/s/o7evmfhx8xn3gfn/tm_guide_theme_change_base.png?raw=1) 35 | 36 | All changes are applied and saved directly. All changes will be immediately visible since your new Theme is selected as your current Theme. 37 | 38 | ![changes are directly visible](https://www.dropbox.com/s/z6sseczp8ccyhui/tm_guide_theme_changes_visible.png?raw=1) 39 | 40 | ## Export / Import a theme 41 | 42 | You can export a custom theme from the **Window -> Theme** and later import it there as well. The Theme will be saved as a `.tm_theme` file. These files are simple `json` like files. 43 | 44 | 45 | 46 | ## Change the Scale of the UI 47 | 48 | In the **Window** menu, you have a menu point **Zoom**. 49 | 50 | ![zom option](https://www.dropbox.com/s/mvdzunm81gj4qj4/tm_guide_window_zoom.png?raw=1) 51 | 52 | This allows you to zoom in or out. You can also use the key bindings: 53 | 54 | | Meaning | Keys | 55 | | -------- | -------------------------------- | 56 | | Zoom In | CTRL + Equal, CTRL + Num + Plus | 57 | | Zoom Out | CTRL + Minus, CTRL + Num + Minus | 58 | 59 | 60 | 61 | ## Custom Layout 62 | 63 | In case you do not like your current layout, you can always restore the default layout by using the **Window -> Restore Default Layout** menu point. 64 | 65 | ![restore default layout](https://www.dropbox.com/s/coy73d8esv1jdew/tm_guide_window_restore_layout.png?raw=1) 66 | 67 | If you want to store your current layout, it would be very useful for the later time you can save your current window layout. 68 | 69 | ![save current layout](https://www.dropbox.com/s/3vfmrnstcrf35gy/tm_guide_window_save_layout.png?raw=1) 70 | 71 | You can create a new window or workspace with a layout in case you need it. 72 | 73 | ![](https://www.dropbox.com/s/dxy29xlb31xsbv9/tm_guide_create_window_with_layout.png?raw=1) 74 | 75 | > **Note:** The Engine should restore the last used layout when it shutdown. 76 | 77 | If you need to change some details of your Window layout you can do this via the Edit layout menu. 78 | 79 | ![edit layout](https://www.dropbox.com/s/bbc8ke0bqgp7vkh/tm_guide_window_edit.png?raw=1) 80 | 81 | This will open the settings of the current Layout: 82 | 83 | ![](https://www.dropbox.com/s/1qt0q6ho4k3jn4d/tm_guide_window_edit_layout.png?raw=1) 84 | 85 | 86 | 87 | ## World Grid 88 | 89 | In case you need to adjust the World Grid, you can do this at two places: 90 | 91 | 1. Via the Application Settings 92 | 93 | ![](https://www.dropbox.com/s/61rdistx6vuxaow/tm_guide_change_grid_settings.png?raw=1) 94 | 95 | 2. Via any Scene or Preview Tab Application Menu entry. 96 | 97 | ![](https://www.dropbox.com/s/doenzd3d3gniq0u/tm_guide_change_grid_scene_tab.png?raw=1) 98 | 99 | Changes made there will only be applied to the specific tab. 100 | 101 | -------------------------------------------------------------------------------- /src/the_editor/preview_tab.md: -------------------------------------------------------------------------------- 1 | # Preview Tab 2 | 3 | The Preview Tab displays selected objects for you. 4 | 5 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625574207263_image.png) 6 | 7 | 8 | **Camera Controls** 9 | It allows for the same Free-Camera controls as the Scene Tab. 10 | 11 | **Movement** 12 | 13 | - **Middle Mouse Button:** Keep pressed down to move through the Scene. 14 | - **Left Mouse Button:** Keep pressed down to rotate in the Scene by rotating the mouse. If you keep the mouse pressed so you can also use **WASD** to move through the Scene. To increase or decrease the movement speed, you need to move the mouse wheel. 15 | 16 | **Zoom in** 17 | 18 | - **Mouse Wheel**: To zoom in, you can zoom in or out via the mouse wheel. 19 | -------------------------------------------------------------------------------- /src/the_editor/properties_tab.md: -------------------------------------------------------------------------------- 1 | # Properties Tab 2 | 3 | The **Properties** tab shows the properties of the currently selected object. You can modify the properties by editing them in the properties window. 4 | 5 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625428761738_image.png) 6 | 7 | ### Use mathematical expression 8 | 9 | We’ve also have support for mathematical expression to our property editor. So you can now type both numerical values and expressions. 10 | 11 | You can use `x` in the expression to mean whatever value the property had before, so if you type `x + 1` you will increase the current value by 1. 12 | 13 | 14 | ![Using expressions in the property editor.](https://paper-attachments.dropbox.com/s_AF44CABDD4BF19FA7D54C2D4574B155CAAE2ED895AFB490AC3671972A5F81DC2_1617121646846_expressions.gif) 15 | 16 | ### Multiple tabs with different properties 17 | 18 | You can have multiple tabs of different properties open if you wish. In this case, it comes very handily that you can pin Properties Tabs to a specific Object. 19 | Otherwise, the property tab will reflect the next selected object, and you would have multiple times the same thing open. 20 | You can pin content by clicking the *Pin* icon on Properties Tab. It will bind the current object to this instance. 21 | 22 | ![Pin the properties tab for the prop floor barrel (module dungeon kit example)](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625428863969_image.png) 23 | 24 | 25 | Moreover, if you dock a *Preview* tab in the same window as an *Asset Browser*, it will show a preview of the selected asset in that browser. 26 | 27 | **About Prototypes** 28 | 29 | The Machinery has a prototype system that allows entity assets to be used within each other. Therefore you can create an Entity-Asset that represents a room and then create a house Entity with a bunch of these room entities placed within. 30 | We call the room asset a *prototype*, and we call each placed room entity an *instance* of this prototype. 31 | 32 | Any Entity-Asset can be a prototype, with instances of it placed in another entity asset. Note that prototypes are not special assets. More about this [here.]({{base_url}}editing_workflows/prototype_workflow/index.html) 33 | 34 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625428959141_image.png) 35 | 36 | 37 | The overridden entities and components are drawn in blue. We change the x and z components of the position to move the box. Note how the changed values are shown in white, while the values inherited from the prototype are shown in grey. 38 | 39 | Missing 40 | 41 | - link somehow somewhere the prototype content 42 | -------------------------------------------------------------------------------- /src/the_editor/simulate_tab.md: -------------------------------------------------------------------------------- 1 | # Simulate Tab 2 | 3 | In *The Machinery*, we make a distinction between *simulating* and *editing*. When you are *editing*, you see a static view of the scene. (Editing the scene with everything moving around would be very tricky.) all the runtime behaviors like physics, animation, destruction, entity spawning, etc., are disabled. 4 | If you are building a game, the simulation mode will correspond to running the game. In contrast, when you are *simulating* or *running*, all the dynamic behaviors are enabled. It allows you to see the runtime behavior of your entities. To *simulate* a scene, open a scene in the *Simulate* tab. 5 | 6 | 7 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625573554323_image.png) 8 | 9 | 10 | **Control over your simulation** 11 | While your simulation is running, you can Stop, reset or speed up the simulation. 12 | 13 | 14 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625573595318_image.png) 15 | 16 | 17 | If your scene contains multiple cameras, you can pick between them via the camera toolbar.The default camera is a free flight camera. 18 | 19 | 20 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625573634527_image.png) 21 | 22 | 23 | In the same toolbar, you can enable Debug-Rendering-Tags from various components. For example, it will render a box around the Volume Component from the Volume Component if enabled. 24 | 25 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625573748963_components.gif) 26 | 27 | 28 | Within this toolbar, you also find the statistic button to open several overlays, such as *Frame Time.* 29 | 30 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625573806537_image.png) 31 | 32 | 33 | Besides those options, you have the *Render* option, which allows for the same options as in the Scene Tab. 34 | -------------------------------------------------------------------------------- /src/the_editor/tabs.md: -------------------------------------------------------------------------------- 1 | ## About Tabs 2 | 3 | The Machinery is based around a collection of editing *Tabs*, each with its specific purpose. You can drag the tabs around to rearrange them. Use the *Tab* menu to open new tabs. It is possible to have multiple tabs of the same type. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | 10 | ## About Tab-Wells 11 | Windows in The Machinery have a root **tab-well** covering the whole window. A tab-wells are rectangular areas containing one or more tabs. You can split them either horizontally or vertically to form two-child tab-wells. Also, you can switch around tabs within a tab-well via the keyboard using Ctrl + 1-9 or via Ctrl Page Up/Down. 12 | 13 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1608290650481_keyboard-record.gif) 14 | 15 | ## Pinning tabs 16 | You can also pin tabs to the current content or other settings with the *pin* icon. 17 | 18 | ![](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625427774726_image.png) 19 | 20 | 21 | It is also possible to use the context menu if you click on the tab label: 22 | 23 | ![right click on the tab label will show this.](https://paper-attachments.dropbox.com/s_688CFE67758A45D845E788E6DA05448A2BCF730C2B07FEF2D06AB18D2C46F736_1625427822543_image.png) 24 | 25 | ### Pinning options 26 | In the context menu, you have more options for pinning. These allow you to manage and arrange the window layout in a way that suits your workflow. The following table will show all the possible options: 27 | 28 | | Option | Description | 29 | | --------------- | ------------------------------------------------------------ | 30 | | Pin via icon ⚲ | Will pin the tab to the current shown content | 31 | | Pin to View 🗖 | This Pins the tab's content to another tab view that is currently open in the current window. You can pin a tab to multiple other tabs at the same time. | 32 | | Pin to Window 🗗 | It pins the current tab to the selected window. For example, if you pin the Properties tab to Window 2. and choose an asset from the Asset Browser, the properties tab in Window 1. will display the selected asset. | 33 | 34 | Besides, it is possible to extend the Engine with custom tabs. You can do this via the **File → New Plugin → Editor Tabs.** How to write your custom tab is out of the scope of this article but is covered [here]({{base_url}}extending_the_machinery/write-a-plugin.html). 35 | 36 | ## Keyboard bindings 37 | 38 | | Key | Description | 39 | | ------------------- | --------------------------------------- | 40 | | Ctrl + Tab | Switch between tabs | 41 | | Ctrl + 1-9 | Switch between tabs in current tab well | 42 | | Ctrl + Page up/Down | Switch between tabs in current tab well | 43 | -------------------------------------------------------------------------------- /src/the_truth/README.md: -------------------------------------------------------------------------------- 1 | # The Truth 2 | 3 | The Machinery uses a powerful data model to represent edited assets. This model has built-in support for serialization, streaming, copy/paste, drag-and-drop as well as unlimited undo/redo. It supports an advanced hierarchical prefab model for making derivative object instances and propagating changes. It even has full support for real-time collaboration. Multiple people can work together in the same game project, Google Docs-style. Since all of these features are built into the data model itself, your custom, game-specific data will get them automatically, without you having to write a line of code. 4 | 5 | ## The Data Model 6 | 7 | The Machinery stores its data as **objects with properties**. Each object has a type and the type defines what properties the object has. Available property types are *bools, integers, floats, strings, buffers, references*, *sub-objects* and *sets of references or sub-objects*. 8 | 9 | The object/properties model gives us us *forward and backward compatibility* and allows us to implement operations such as *cloning* without knowing any details about the data. We can also represent modifications to the data in a uniform way `(object, property, old-value, new-value)` for undo/redo and collaboration. 10 | 11 | The model is **memory-based** rather than disk-based. I.e. the in-memory representation of the data is considered *authoritative.* Read/write access to the data is provided by a thread-safe API. If two systems want to cooperate, they do so by talking to the same in-memory model, not by sharing files on disk. Of course, we still need to save data out disk at some point for persistence, but this is just a “backup” of the memory model and we might use different disk formats for different purposes (i.e. a git-friendly representation for collaborative work vs single binary for solo projects). 12 | 13 | Since we have a memory-based model which supports cloning and change tracking, copy/paste and undo can be defined in terms of the data model. Real-time collaboration is also supported, by serializing modifications and transmitting them over the network. Since the runtime has equal access to the data model, modifying the data from within a VR session is also possible. 14 | 15 | We make a clear **distinction between “buffer data” and “object data”**. *Object data* is stuff that can be reasoned about on a per-property level. I.e. if user A changes one property of an object, and user B changes another, we can merge those changes. *Buffer data* are binary blobs of data that are opaque to the data model. We use it for large pieces of binary data, such as textures, meshes and sound files. Since the data model cannot reason about the content of these blobs it can’t for example merge changes made to the same texture by different users. 16 | 17 | Making the distinction between buffer data and object data is important because we pay an overhead for representing data as objects. We only want to pay that overhead when the benefits outweigh the costs. Most of a game’s data (in terms of bytes) is found in things like textures, meshes, audio data, etc and does not really gain anything from being stored in a JSON-like object tree. 18 | 19 | In The Truth, **references are represented by IDs**. Each object has a unique ID and we reference other objects by their IDs. Since references have their own property type in The Truth, it is easy for us to reason about references and find all the dependencies of an object. 20 | 21 | Sub-objects in The Truth are references to *owned* objects. They work just as references, but have special behaviours in some situations. For example, when an object is cloned, all its sub-objects will be cloned too, while its references will not. 22 | 23 | For more information checkout the [documentation]({{docs}}foundation/the_truth.h.html) and these blog posts: [The Story behind The Truth: Designing a Data Model](https://ourmachinery.com/post/the-story-behind-the-truth-designing-a-data-model/) or this [one](https://ourmachinery.com/post/multi-threading-the-truth/). 24 | 25 | -------------------------------------------------------------------------------- /src/the_truth/access_values.md: -------------------------------------------------------------------------------- 1 | # Access values 2 | 3 | The truth objects (`tm_tt_id_t`) are immutable objects unless you explicitly make them writable. Therefore you do not have to be afraid of accidentally changing a value when reading from an object property. 4 | 5 | To read from an object property we need access to the correct Truth Instance as well as to an object id. We also need to know what kind of property we want to access. That is why we always want to define our properties in a Header-File. Which allows us and others to find quickly our type definitions. A good practice is to comment on what kind of data type property contains. 6 | 7 | Let us assume our object is of type ``TM_TT_TYPE__RECT``: 8 | 9 | ``` 10 | enum { 11 | TM_TT_PROP__RECT__X, // float 12 | TM_TT_PROP__RECT__Y, // float 13 | TM_TT_PROP__RECT__W, // float 14 | TM_TT_PROP__RECT__H, // float 15 | }; 16 | ``` 17 | 18 | When we know what we want to access, we call the correct function and access the value. In our example we want to get the width of an object. The width is stored in `TM_TT_PROP__RECT__W`. 19 | 20 | The function we need to call: 21 | 22 | ```c 23 | void (*get_float)(tm_the_truth_o *tt,const tm_the_truth_object_o *obj, uint32_t property); 24 | ``` 25 | 26 | With this knowledge we can assemble the following function that logs the width of an object: 27 | 28 | ```c 29 | void log_with(tm_the_truth_o *tt, tm_tt_id_t my_object){ 30 | const float width = tm_the_truth_api->get_float(tt,tm_tt_read(tt,my_object),TM_TT_PROP__RECT__W); 31 | TM_LOG("the width is %f",width); 32 | } 33 | ``` 34 | 35 | 36 | 37 | ## Make the code robust 38 | 39 | To ensure we are actually handling the right type we should check this at the beginning of our function. If the type is not correct we should early out and log a warning. 40 | 41 | All we need to do is compare the `tm_tt_type_t`'s of our types. Therefore we need to obtain the type id from the object id and from our expected type. From a `tm_tt_id_t` we can obtain the type by calling `tm_tt_type()` on them. `tm_the_truth_api->object_type_from_name_hash(tt, TM_TT_TYPE_HASH__MY_TYPE);` will give us back the object type from a given hash. After that we can do our comparison. 42 | 43 | ```c 44 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/access_values.c,access_values)}} 45 | ``` 46 | 47 | > **Note:** Check out the logger documentation for more information on it. [log.h]({{docs}}foundation/log.h.html#log.h) 48 | 49 | -------------------------------------------------------------------------------- /src/the_truth/aspects.md: -------------------------------------------------------------------------------- 1 | # Aspects 2 | 3 | An “aspect” is an interface (struct of function pointers) identified by a unique identifier. The Truth allows you to associate aspects with object types. This lets you extend The Truth with new functionality. For example, you could add an interface for debug printing an object: 4 | 5 | ```c 6 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/truth_mixed.c,debug_aspect)}} 7 | ``` 8 | 9 | > **Note:** to genereate the `TM_STATIC_HASH` you need to run `hash.exe` or `tmbuild.exe --gen-hash` for more info open the [hash.exe guide]({{base_url}}/build_tools/hash.html) 10 | 11 | You could then use this code to debug print an object `o` with: 12 | 13 | ```c 14 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/truth_mixed.c,example_use_case)}} 15 | ``` 16 | 17 | > **Note**: that plugins can extend the system with completely new aspects. 18 | 19 | 20 | 21 | The best example of how the Engine is using the aspect system is the `tm_properties_aspect_i` which helps us to defines custom UIs for Truth objects. -------------------------------------------------------------------------------- /src/the_truth/common_types.md: -------------------------------------------------------------------------------- 1 | # Common Types 2 | 3 | The Truth comes with several useful common types. You can find them in the `the_truth_types. ([API Documentation]({{docs}}foundation/the_truth_types.h.html#structtm_the_truth_common_types_api)). 4 | 5 | 6 | 7 | | Macro | Description | 8 | | ------------------------------------------------------------ | ------------------------------------------------------------ | 9 | | `TM_TT_TYPE__BOOL`/`TM_TT_TYPE_HASH__BOOL` | The first property contains the value. | 10 | | `TM_TT_TYPE__UINT32_T`/`TM_TT_TYPE_HASH__UINT32_T` | The first property contains the value. | 11 | | `TM_TT_TYPE__UINT64_T`/`TM_TT_TYPE_HASH__UINT64_T`| The first property contains the value. | 12 | | `TM_TT_TYPE__FLOAT`/`TM_TT_TYPE_HASH__FLOAT`| The first property contains the value. | 13 | | `TM_TT_TYPE__DOUBLE` /`TM_TT_TYPE_HASH__DOUBLE` | The first property contains the value. | 14 | | `TM_TT_TYPE__STRING`/`TM_TT_TYPE_HASH__STRING` | The first property contains the value. | 15 | | `TM_TT_TYPE__VEC2`/`TM_TT_TYPE_HASH__VEC2` | The first property contains the x value and the second the y value. | 16 | | `TM_TT_TYPE__VEC3`/`TM_TT_TYPE_HASH__VEC3`| The first property contains the x value and the second the y value and the third the z value. | 17 | | `TM_TT_TYPE__VEC4`/`TM_TT_TYPE_HASH__VEC4`| The first property contains the x value and the second the y value and the third the z value while the last one contains the w value. | 18 | | `TM_TT_TYPE__POSITION`/`TM_TT_TYPE_HASH__POSITION` | Same as `vec4`. | 19 | | `TM_TT_TYPE__ROTATION`/`TM_TT_TYPE_HASH__ROTATION` | Based on a `vec4`. Used to represent the rotation of an object via quaternions. | 20 | | `TM_TT_TYPE__SCALE`/`TM_TT_TYPE_HASH__SCALE` | Same as `vec3.` | 21 | | `TM_TT_TYPE__COLOR_RGB`/`TM_TT_TYPE_HASH__COLOR_RGB`| Represents a RGB colour. | 22 | | `TM_TT_TYPE__COLOR_RGBA`/`TM_TT_TYPE_HASH__COLOR_RGBA`| Represents a RGBA colour. | 23 | | `TM_TT_TYPE__RECT`/`TM_TT_TYPE_HASH__RECT` | The first property contains the x value and the second the y value and the third the width value while the last one contains the height value. | 24 | 25 | There is a helper API to handle all of these types in an easy way, to reduce the boilerplate code: `tm_the_truth_common_types_api`. 26 | 27 | > **Note:** There is a list of all Truth Types the Engine comes with available on our [API Documentation]({{docs}}truth_types.html) 28 | -------------------------------------------------------------------------------- /src/the_truth/create_an_object.md: -------------------------------------------------------------------------------- 1 | ## Create an Object 2 | 3 | You can create an object of a Truth Type via two steps: 4 | 5 | 1. You need to obtain the Type from the type hash. We call the `object_type_from_name_hash` to obtain the `tm_tt_type_t` 6 | 2. You need to create an Object from that Type. We call `create_object_of_type` to create an object `tm_tt_id_t` . We pass `TM_TT_NO_UNDO_SCOPE` because we do not need an undo scope for our example. 7 | 8 | First, we need to have access to a Truth instance. Otherwise, we could not create an object. In this example, we create a function. 9 | 10 | ```c 11 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/create_an_object.c,create_my_type_object)}} 12 | ``` 13 | 14 | Wherever we call this function we can then edit and modify the type and add content to it! 15 | 16 | The alternative approach is to use the "Quick Object Creation function". 17 | 18 | ```c 19 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/create_an_object.c,quick_create_my_type_object)}} 20 | ``` 21 | 22 | 23 | 24 | > **Note:** need to pass `-1` to tell the function that we are at the end of the creation process. More info [here]({{docs}}foundation/the_truth.h.html#structtm_the_truth_api.quick_create_object()). 25 | 26 | 27 | 28 | ## What is next? 29 | 30 | If you want to learn more about how to create your own custom type, follow the ["Custom Truth Type"]({{base_url}}/the_truth/custom_truth_type.html) walkthrough. 31 | -------------------------------------------------------------------------------- /src/the_truth/modify_an_object.md: -------------------------------------------------------------------------------- 1 | # Modify an object 2 | 3 | To manipulate an object, you need to have its ID (`tm_tt_id_t`). When you create an object, you should keep its ID around if you intend to edit it later. 4 | 5 | **Table of Content** 6 | 7 | * {:toc} 8 | 9 | In this example, we have a function that gets an object and the Truth instance of that object. 10 | 11 | ```c 12 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object)}} 13 | ``` 14 | 15 | > **Important:** you can only edit an object that is part of the same instance! Hence your `my_object` must be created within this instance of the Truth (`tt`). 16 | 17 | 18 | 19 | ## 1. Make the object writable 20 | 21 | To edit an object, we need to make it writable first. In the default state, objects from the Truth are immutable. The Truth API has a function that is called `write`. When we call it on an object, we make it writable. 22 | 23 | ```c 24 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object_alt_write)}} 25 | ``` 26 | 27 | ## 2. Write to the object. 28 | 29 | We need to know what kind of property we want to edit. That is why we always want to define our properties in a Header-File. A good practice is to comment on what kind of data type property contains. 30 | 31 | Let us assume our object is of type ``TM_TT_TYPE__RECT``: 32 | 33 | ``` 34 | enum { 35 | TM_TT_PROP__RECT__X, // float 36 | TM_TT_PROP__RECT__Y, // float 37 | TM_TT_PROP__RECT__W, // float 38 | TM_TT_PROP__RECT__H, // float 39 | }; 40 | ``` 41 | 42 | In our example we want to set the width to `100`. The width is stored in `TM_TT_PROP__RECT__W`. 43 | 44 | When we know what we want to edit, we call the correct function and change the value. 45 | 46 | The function we need to call: 47 | 48 | ```c 49 | void (*set_float)(tm_the_truth_o *tt, tm_the_truth_object_o *obj, uint32_t property,float value); 50 | ``` 51 | 52 | Let us bring all of this together: 53 | 54 | ```c 55 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object_alt)}} 56 | ``` 57 | 58 | 59 | 60 | ## 3. Save the change 61 | 62 | In the end, we need to commit our change to the system. In this example we do not care about the undo scope. That is why we provide the `TM_TT_NO_UNDO_SCOPE` define. This means this action is not undoable. 63 | 64 | ```c 65 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object_noundo)}} 66 | ``` 67 | 68 | If we wanted to provide an undo scope we need to create one: 69 | 70 | ```c 71 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object_alt,off)}} 72 | ``` 73 | 74 | Now this action can be reverted in the Editor. 75 | 76 | 77 | 78 | ## 4. Get a value 79 | 80 | Instead of changing the value of width to 100 we can also increment it by 100! All we need to do is get the value first of the Truth Object and add 100 to it. To access a property we need to use the macro `tm_tt_read`. This will give us an immutable (read only) pointer to the underlying object. This allows us to read the data from it. 81 | 82 | ```c 83 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify)}} 84 | ``` 85 | 86 | > **Note:** If we had a lot of read actions we should only call `tm_tt_read` once and store the result in a `const tm_the_truth_object_o*` variable and reuse. 87 | 88 | 89 | 90 | ## 5. Make the code robust 91 | 92 | To ensure we are actually handling the right type we should check this at the beginning of our function. If the type is not correct we should early out. 93 | 94 | All we need to do is compare the `tm_tt_type_t`'s of our types. Therefore we need to obtain the type id from the object id and from our expected type. From a `tm_tt_id_t` we can obtain the type by calling `tm_tt_type()` on them. `tm_the_truth_api->object_type_from_name_hash(tt, TM_TT_TYPE_HASH__MY_TYPE);` will give us back the object type from a given hash. After that we can do our comparison. 95 | 96 | ```c 97 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/truth/modify_object.c,modify_my_object,off)}} 98 | ``` 99 | 100 | -------------------------------------------------------------------------------- /src/tutorials/README.md: -------------------------------------------------------------------------------- 1 | # Tutorials -------------------------------------------------------------------------------- /src/tutorials/creation_graph/README.md: -------------------------------------------------------------------------------- 1 | # Creation Graph 2 | 3 | In The Machinery, we provide full control over how data enters the engine and what data-processing 4 | steps get executed, allowing technical artists to better optimize content and setup custom, 5 | game-specific asset pipelines. 6 | 7 | This is handled through [*Creation Graphs*]({{base_url}}/creation_graphs/concept.html). A Creation Graph is essentially a generic framework for 8 | processing arbitrary data on the CPUs and GPUs, exposed through a graph front-end view. While *Creation Graphs* are mostly used in the context of rendering, they can be used for any type of data processing. 9 | 10 | The following section will guide you from basic use cases to more advanced use cases. 11 | 12 | We have a couple of blog posts which you may also find interesting: 13 | 14 | - [Creation Graphs](https://ourmachinery.com/post/creation-graphs/) 15 | - [More on Creation Graphs](https://ourmachinery.com/post/more-on-creation-graphs/) 16 | - [Summer Fun with Creation Graphs](https://ourmachinery.com/post/summer-fun-with-creation-graphs/) 17 | 18 | -------------------------------------------------------------------------------- /src/tutorials/creation_graph/custom_cpu_nodes.md: -------------------------------------------------------------------------------- 1 | # Creating custom CPU nodes 2 | 3 | In this tutorial we will create a simple CPU node for the [*Creation Graph*]({{base_url}}/creation_graphs/concept.html). The definition for these nodes is based on the Entity Graph Nodes, so there is some overlap. For this example we will create a node that generates a random `uint32_t` node with a settable maximum. To learn the difference between CPU and GPU nodes, check out [*Node Types*]({{base_url}}/creation_graphs/node_types.html). 4 | 5 | ![](https://www.dropbox.com/s/04s5rzhmg9iwz68/tut_creation_graph_cpu_random.png?raw=1) 6 | 7 | Let’s first create the code for this node. This function will be called by the creation graph every time it needs to evaluate the node. Our only input to this function is the context of the creation graph. The first thing we will do is read our input from the context. We can query wires from the `tm_creation_graph_interpreter_api` using the `read_wire()` function. If this wire is not connected (or set directly) we early out with an error. After this, we start writing to our output wire. Note that this uses a very similar syntax, expect that we write to a pre-allocated pointer. 8 | 9 | > **Note** that the indices of these wires is relative to the way they are defined. Our input wire is defined first so its index is 0. The output wire is defined second so it gets the index 1. 10 | 11 | ```c 12 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_cpu_nodes.c,custom_cpu_node_fn)}} 13 | ``` 14 | 15 | We need to register this node to the creation graph API. This is done through the creation graph node interface. We define the general information to the node like its `name`, `display_name` and I/O connectors (wires), and the actual function to run: 16 | 17 | ```c 18 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_cpu_nodes.c,custom_cpu_node_node)}} 19 | // register in the load function 20 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_cpu_nodes.c,custom_cpu_node_register)}} 21 | ``` 22 | 23 | This is the full code to define this creation graph CPU node: 24 | 25 | ```c 26 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_cpu_nodes.c)}} 27 | ``` -------------------------------------------------------------------------------- /src/tutorials/creation_graph/custom_geometry_node.md: -------------------------------------------------------------------------------- 1 | # Creating Custom Geometry Nodes 2 | 3 | In this tutorial we well be creating a CPU node for the [*Creation Graph*]({{base_url}}/creation_graphs/concept.html) that creates a mesh that can be used by rendering nodes. This tutorial expects some basic knowledge of the creation graph and node creation. it is recommended to read [*Creating custom CPU nodes*]({{base_url}}/tutorials/creation_graph/custom_cpu_nodes.html) before reading this. 4 | 5 | ![](https://www.dropbox.com/s/5xbu16zov1k5h4b/tm_tut_creation_graph_geometry_node.png?raw=1) 6 | 7 | The main output of this node will be a `tm_gpu_geometry_t` and a `tm_renderer_draw_call_info_t`. Together these will make out `GPU Geometry` output. Additionally we will be outputting a bounding box for the triangle that can be used for culling and other calculations. But before we can populate those, we’ll need to consider the vertex format of our mesh. For this example, this will be a simple position, normal, and color per vertex: 8 | 9 | ```c 10 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,custom_geometry_node_data)}} 11 | ``` 12 | 13 | The `tm_renderer_draw_call_info_t` is constant for our example so we can populate it as follows: (note that this node doesn’t create an index buffer and thusly uses `TM_RENDERER_DRAW_TYPE_NON_INDEXED`) 14 | 15 | ```c 16 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,custom_geometry_node_call_info)}} 17 | ``` 18 | 19 | Creating the geometry for this node requires us to take several things into consideration. First, we need to store the vertex buffer, constant buffer, and resource binder somewhere. Thankfully, the creation graph has a resource caching system that will handle this storage for us. Second, we need to define the system required to query our mesh primitives. For most use cases, the default `vertex_buffer_system` is the best option. Third, we need to ask ourselves what this geometry will be used for. If the geometry should be visible to the ray tracing pipeline for instance. This is a design choice that should be made by the node creator. In this example, we will take ray tracing into account. 20 | 21 | First, let us query the default `vertex_buffer_system`, if this is not available our node will not work so we can early out: 22 | 23 | ```c 24 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,vertex_buffer_system)}} 25 | ``` 26 | 27 | Next we will be creating the resources needed for our node. This will be a `tm_shader_constant_buffer_instance_t`, a `tm_shader_resource_binder_instance_t`, and a GPU buffer: 28 | 29 | ```c 30 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,create_resource)}} 31 | ``` 32 | 33 | Now that our buffer has been created; we can start populating it with our vertex data: 34 | 35 | ```c 36 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,vertex_data)}} 37 | ``` 38 | 39 | Finally, we need to tell the `vertex_buffer_system` which primitives are available in our mesh and how it should access them. This is what the constant buffer and resource binder are for. Note that the layout for the vertex buffer system can be included from the `vertex_buffer_system.inl` file: 40 | 41 | ```c 42 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,buffer_system)}} 43 | ``` 44 | 45 | And now we have our triangle, we just have to unlock the resource cache again and set the bounding volume outputs: 46 | 47 | ```c 48 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c,unlock)}} 49 | ``` 50 | 51 | This is the full source code to define this creation graph CPU node: 52 | 53 | ```c 54 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/custom_geometry_node.c)}} 55 | ``` -------------------------------------------------------------------------------- /src/tutorials/creation_graph/from_code.md: -------------------------------------------------------------------------------- 1 | # Calling Creation Graphs from Code 2 | 3 | In this tutorial we will create a very simple component that uses a [Creation Graph]({{base_url}}/creation_graphs/concept.html) to render to the viewport. The Creation Graph used for this example can be seen in the image below. 4 | 5 | The goal of this Creation Graph is to create an image output that we can copy to the viewport. In this example, the image is created by the creation graph and the viewport UV is rendered onto it using an unlit pass. Notice that no geometry has to be defined, as we use the `Construct Quad` node in clip space. This will procedurally encompass the entire viewport. 6 | 7 | **Contents** 8 | * {:toc} 9 | 10 | ![](https://www.dropbox.com/s/k4y8wlwx7y8vll3/tm_tut_creation_graphs_from_code.png?raw=1) 11 | 12 | ## Using the Creation Graph API 13 | The component itself is very simple, it only has a single property which is our creation graph asset: 14 | 15 | ```c 16 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c,gc_asset)}} 17 | ``` 18 | 19 | However multiple fields are defined in the runtime component struct, all of these are dependent on our creation graph: 20 | 21 | ```c 22 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c,component)}} 23 | ``` 24 | 25 | In the example, we only call the creation graph once (during the initialization phase). The workflow is as follows. 26 | The creation graph subobject is added by The Truth, so we don’t have to do any UI or linking code for it. 27 | In the initialize function, we instantiate this creation graph asset with a default context. 28 | This updates our image output node and all the nodes it is dependent upon: 29 | 30 | ```c 31 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c,init_phase)}} 32 | ``` 33 | 34 | Next we query all the image output nodes from the graph and pick the first one. The information we get from the output node is enough to copy our image to the viewport: 35 | 36 | ```c 37 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c,query_image)}} 38 | ``` 39 | 40 | To do this we register it to the viewport's render graph using `register_gpu_image()` and then pass it to the `debug_visualization_resources` for easy rendering to the screen: 41 | 42 | ```c 43 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c,itr)}} 44 | ``` 45 | 46 | ## Remarks 47 | Note that this is a very simple example of the creation graph. We don’t update it every frame so it will only render once. This makes use of the `Time` node useless in this example. Note as well that we are not triggering any wires, this also means that the `Init event` node will never be called by the component. 48 | 49 | Also, all destruction code has been omitted from the code sample to shorten it. In a production implementation, the creation graph instance and the component should be destroyed. 50 | 51 | ## Full Code 52 | ```c 53 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/creation_graph/calling_creation_graph_from_code.c)}} 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /src/tutorials/creation_graph/introduction_walkthrough/README.md: -------------------------------------------------------------------------------- 1 | # Creation Graph Introduction 2 | 3 | This walkthrough shows you some basics of the [Creation Graph]({{base_url}}/creation_graphs/concept.html). During this walkthrough series you will familiarize yourself with the following concepts: 4 | 5 | - What Are Creation Graphs? 6 | - Simple Texture Compression 7 | - Graph Prototypes 8 | - Custom Import Settings 9 | - Materials 10 | - DCC Mesh Graph & Render Component 11 | 12 | ## Video 13 | 14 | 15 | 16 | ## Introduction 17 | 18 | This walkthrough series makes use of the following free assets: 19 | 20 | * [KhronosGroup](https://github.com/KhronosGroup)/**[glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)**. 21 | 22 | During this series we will modify the assets. If you are interested in how to import assets into the Engine you can watch the video [Import and rigging tutorial](https://www.youtube.com/watch?v=loaYaeSl-_g&t=20s) or you follow theGuide [Import assets](https://ourmachinery.github.io/themachinery-books/the_machinery_book/editing_workflows/import_assets.html#import-assets). Besides this, this series has one main goal: to familiarize you with the "Core Creation Graphs" that we ship with the Engine in the core folder. Most creation graphs that the engine uses are built on top of those. 23 | -------------------------------------------------------------------------------- /src/tutorials/creation_graph/introduction_walkthrough/creation_graph_prototype.md: -------------------------------------------------------------------------------- 1 | # Creation Graph Prototypes 2 | 3 | This walkthrough shows you some basics of the [Creation Graph]({{base_url}}/creation_graphs/concept.html). In this part we discuss creation graph prototypes. To read more in general about the prototype system please checkout the following [Guide: Prototypes]({{base_url}}editing_workflows/prototype_workflow/index.html) 4 | 5 | > **Note:** The walkthrough series makes use of the following free assets: [KhronosGroup](https://github.com/KhronosGroup)/**[glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)**. 6 | 7 | This tutorial will teach you: 8 | 9 | - How to create Creation Graph prototypes 10 | - How to apply them to multiple assets 11 | - How to add extra input 12 | 13 | 14 | 15 | 16 | 17 | ## Setup 18 | 19 | We could do this by opening all textures and following the steps described in the [Simple Texture Compression Walkthrough]({{base_url}}/tutorials/creation_graph/introduction_walkthrough/texture_compression.html) but this would be a time consuming and error prone job. It would be easier to just create one prototype for all. 20 | 21 | ## Adding texture compression to all textures in the project 22 | 23 | ### Creating a Creation Graph Prototype 24 | 25 | There are 2 effective ways of doing this: 26 | 27 | 1. Change the prototype of all dcc images use: `core/creation_graphs/dcc-image` 28 | 29 | We open this prototype and apply all our changes described in [Simple Texture Compression Walkthrough]({{base_url}}/tutorials/creation_graph/introduction_walkthrough/texture_compression.html). Changes to the prototype will propagate to all creation graph instances of this prototype. 30 | 31 | 32 | 33 | 2. Create a new creation graph and base it on `core/creation_graphs/dcc-image` 34 | 35 | In this alternative approach we create with **Right Click** in the asset browser and then **New -> Creation Graph** a new creation graph. This graph is a empty graph. When we select the newly created asset we can chose in the property view tab the prototype of the asset. 36 | 37 | {image} 38 | 39 | In this selection we search for `dcc-image` and base (inherit) our new creation graph on the existing creation graph. After this we can modify this graph as described in the [Simple Texture Compression Walkthrough]({{base_url}}/tutorials/creation_graph/introduction_walkthrough/texture_compression.html). 40 | 41 | ### Applying the new prototype to all texture assets 42 | 43 | Now we select all assets in the asset browser and change their creation graph to point to our newly creation creation graph 44 | 45 | {image} 46 | 47 | 48 | 49 | ### Expose compression settings to the outside world 50 | 51 | Now one problem is left it is that some of these are normal maps and for those you want different compression settings. The fix for this is to expose the Compression Node settings to the outside world. We open our newly creation creation graph connect the compression settings of the compression node with the input connector of the Input node. The original default value stays the default value of our graph Do not forget to mark them as public in the input node properties. 52 | 53 | {image} 54 | 55 | When this is done you can see the exposed settings when ever you select any asset in the asset browser. 56 | 57 | {image} 58 | 59 | What ever you change here will be passed to the compression node. This makes sure that normal maps can be treated how they are supposed to. -------------------------------------------------------------------------------- /src/tutorials/creation_graph/introduction_walkthrough/texture_compression.md: -------------------------------------------------------------------------------- 1 | # Texture Compression 2 | 3 | This walkthrough shows you some basics of the [Creation Graph]({{base_url}}/creation_graphs/concept.html). In this part we discuss texture compression. 4 | 5 | This tutorial will teach you: 6 | 7 | - How to compress a texture 8 | - What differentiates a creation graph from each other. 9 | 10 | 11 | 12 | > **Note:** walkthrough series makes use of the following free assets: [KhronosGroup](https://github.com/KhronosGroup)/**[glTF-Sample-Models](https://github.com/KhronosGroup/glTF-Sample-Models)**. 13 | 14 | 15 | 16 | ## Setup 17 | 18 | Download the flight helmet asset from the git repo [Download Now](https://downgit.github.io/#/home?url=https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/FlightHelmet/glTF). After we have downloaded and extracted all parts of the dcc asset as described in [Import and rigging tutorial](https://www.youtube.com/watch?v=loaYaeSl-_g&t=20s) or you follow this Guide [Import assets](https://ourmachinery.github.io/themachinery-books/the_machinery_book/editing_workflows/import_assets.html#import-assets). We can follow the rest of the tutorial. 19 | 20 | 21 | 22 | ## How do we identify uncompressed images? 23 | 24 | When we select a texture in the Asset Browser, lets select the leather of the helmet. 25 | 26 | {image} 27 | 28 | In the preview tab we can see that this texture is uncompressed indicated by the text line in the bottom of the preview. 29 | 30 | {image} 31 | 32 | ## How do we compress the texture? 33 | 34 | We double click the selected texture and open its creation graph. This will open the instanced version of the core `dcc_texture`creation graph. This creation graph looks as following: 35 | 36 | {image} 37 | 38 | ### Dissection 39 | 40 | Let us dissect the graph step by step: 41 | 42 | | Input Node | 43 | | --------------- | 44 | | DCC Asset Image | 45 | | Image Settings | 46 | 47 | The Input node takes a `dcc asset image` this is a data container that contains the raw image data within the dcc asset. This raw data needs to be translated to a GPU image with the next node. 48 | 49 | | DCC Images | 50 | | --------------- | 51 | | DCC Asset Image | 52 | | GPU Image | 53 | 54 | After this translation we can make use of the `Import Settings` to filter the Image with the `Filter Image`. This node filters for example mipmap. 55 | 56 | | Filter Image | 57 | | ------------ | 58 | | Settings | 59 | | Image | 60 | | GPU Image | 61 | 62 | The output is a modified GPU Image which we pass to the `Image Output` node. 63 | 64 | ### How to Distinguish between creation graphs and creation graph. 65 | 66 | The output nodes define the types of the creation graph. In this particular case the creation graph represents a texture now. 67 | 68 | 69 | 70 | ### Add the compression node 71 | 72 | We are using the `crunch` library for our image compression node. We can just press space and search for the "Compression Node" and add it to the graph. Since we are working in an Instance of the core graph we can modify this graph and the results will not change the prototype. 73 | 74 | | Compression Node | 75 | | ------------------ | 76 | | Image | 77 | | GPU Image | 78 | | Input Colour Space | 79 | | Output Format | 80 | | Release GPU Input | 81 | 82 | This node outputs an Image that is compressed and we can then connect this node to the Image Output node. Important to remember is that we need to remove the connection from the output node to the image filter node and remove the original connection. 83 | 84 | {image} 85 | 86 | If we now investigate the image in the asset browser we can see that the texture is compressed. 87 | 88 | {image} 89 | -------------------------------------------------------------------------------- /src/tutorials/network/README.md: -------------------------------------------------------------------------------- 1 | # Networking 2 | 3 | ## Animation Sample 4 | 5 | This tutorial will transform the [Animation Sample](https://ourmachinery.com/samples.html) project to a networked version: 6 | 7 | - [Part 1: Network Assets (Introduction)]({{base_url}}/tutorials/network/animation_sample/network_assets.html) 8 | - [Part 2: Netwokr Instances]({{base_url}}/tutorials/network/animation_sample/multiple_network_instances.html) 9 | - [Part 3: Entity Control]({{base_url}}/tutorials/network/animation_sample/entity_control.html) 10 | - [Part 4: Support Multiple Players]({{base_url}}/tutorials/network/animation_sample/support_multiple_players.html) 11 | - [Part 5: Basic Graph Variable Replication]({{base_url}}/tutorials/network/animation_sample/basic_graph_variables.html) 12 | - [Part 6: Smooth Animation]({{base_url}}/tutorials/network/animation_sample/smooth_animation.html) 13 | - [Part 7: Spawning Entities]({{base_url}}/tutorials/network/animation_sample/spawning_entities.html) 14 | -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/basic_graph_variables.md: -------------------------------------------------------------------------------- 1 | # Part 5: Basic Graph Variable replication 2 | 3 | In this tutorial you’ll learn how to replicate a graph variable across the network. This tutorial build on the learnings of the pervious tutorial: [Part 4]({{base_url}}/tutorials/network/animation_sample/support_multiple_players.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | 8 | ## Video 9 | 10 | 11 | ## Tutorial 12 | 13 | Even if we’re supporting multiple players, when they move and look around the animation it’s not smooth everywhere: if there are clients A and B connected, nobody is telling client B about where client A is moving or looking, and so client B will only rely on the state updates that comes every second from the server to update the position and orientation of client A in its own simulation. 14 | 15 | Let’s first tackle the problem of broadcasting the facing direction of a client to all the other clients. 16 | 17 | If you take a look at the *Pan* subgraph of the *xbot* entity, you’ll see that we are computing a small angle offset every frame and adding that to the current entity rotation via a quaternion multiplication. But Client B is not receiving the input for Client A and so this computation will always result in a null rotation. 18 | 19 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635346537911_image.png) 20 | 21 | So we need to do three things: 22 | 23 | 1. make sure that each client accumulate the correct angle for its own player entity in a graph variable and use that directly to drive the orientation 24 | 2. replicate this variable from each client to the server 25 | 3. broadcast the variable from the server to all the other clients 26 | 27 | -we can use the *Set* and *Get float variable* nodes and reorganize our graph a bit to accomplish 1. 28 | 29 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343525826_image.png) 30 | 31 | -To solve 2, We then simply convert the *Set float variable* node in a *Float variable network replication* node, specifying the fact that only *clients* should set and replicate the variable using the *Network is of type* node. 32 | 33 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343619084_image.png) 34 | 35 | > **Note**: when you pass a null connection to the *network is of type* node you are implicitly asking the type of the “local” simulation. 36 | 37 | 3. is automatically done by the server: the moment it receives the variable update from the client it will automatically replicate the change to all the connected nodes. So we don’t have to do anything for this. 38 | 39 | And now each client has the correct information about where each other client is looking at, and can animate the orientation of other players smoothly. -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/entity_control.md: -------------------------------------------------------------------------------- 1 | # Part 3: Entity Control 2 | 3 | In this tutorial you’ll learn how to set the control of a specific entity and remap its input source. This tutorial build on the learnings of the pervious tutorial: [Part 2]({{base_url}}/tutorials/network/animation_sample/multiple_network_instances.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | ## Video 8 | 9 | 10 | ## Tutorial 11 | We now want to make sure that the movement and facing direction of our player on the *Server* are controlled by the Keyboard and mouse input that is detected on the *Client.* 12 | 13 | There’s a special purpose node that we can use to do exactly that: let’s add a “Set Entity Control” node to the Entity Graph of the World Entity: we want to bind the control of the *xbot* entity to the Client that connects to our server, so we will take the output from the *Connection Accepted* node and chain it to the *Set Entity Control* node. 14 | 15 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342858285_image.png) 16 | 17 | We also need to tell the server that it should use the input that comes from the *Client* for the *xbot* Entity: we can use the *Remap Input* node to do so. 18 | 19 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342886611_image.png) 20 | 21 | We also need to tell the *Client* that the input for the *Xbot* entity has to be taken from its own keyboard/mouse input: we’ll add the *Remap input* node as well once the *Acquired Entity Control* event is triggered on the client. 22 | 23 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342925053_image.png) 24 | 25 | Now that we’ve remapped the input to come from the correct source, let’s convert all of the *Poll Key* and *Poll Mouse Motion* nodes in *Poll Key for Entity* and *Poll Mouse Motion for Entity* in the Graph of the *xbot* entity: this will make sure that instead of blindly using the local input to drive this entity, we’ll be a bit more smart and use the correct input: either the local one (Client) or the remote one that comes from the Client (Server). You can do this by using the “Covert” feature: right click on a node and click “convert” to see all the nodes that you can convert that node into. 26 | 27 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343013043_image.png) 28 | 29 | So the Client is now transmitting the Input to the server (while using the keyboard/mouse input to drive it’s own player entity), and the *server* is instead using that input to drive its simulation instead. -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/multiple_network_instances.md: -------------------------------------------------------------------------------- 1 | # Part 2: Running Multiple Network Instances 2 | 3 | In this tutorial you’ll learn how to run multiple simulation instances at the same time. This tutorial build on the learnings of the pervious tutorial: [Part 1]({{base_url}}/tutorials/network/animation_sample/network_assets.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | ## Video 8 | 9 | 10 | ## Tutorial 11 | Now that we have setup our two Network Assets we want to make sure that when we start our simulation both a Client and a Server instances are created, each in its own Simulate Tab. 12 | 13 | We can do that changing the Network Settings: File→Settings→Networrk Settings: let’s add a Server Instance and a Client Instance. 14 | 15 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342679832_image.png) 16 | 17 | If we run the simulation now you will see an empty world on the Client: the reason is that the Client Asset has been setup to start with an empty world, and no entities in the Server world are currently being replicated to the Client: Let’s fix this by making the World Entity Replicated via the Entity Tree. 18 | 19 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342731213_image.png) 20 | 21 | And if we run the simulation again we’ll now see that the Client is correctly receiving updates from the Server about the World Entity: we can move the Xbot Entity in both windows exactly like in the single player game, but now when we move on the Server Window you’ll notice that the updates are sent to the Client as well: that is because we automatically check for changes in the components of all the entitites that have been flagged as replicated (once per second by default). 22 | 23 | If we instead move the Player from the Client window, you’ll see that the Player on the Server entity doesn’t get updated: we told the Client to have a passive Gamestate, and so even if the Client is simulating the Player on its own simulation instance it doesn’t send the updates to the Server. 24 | 25 | 26 | 27 | 28 | 29 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343311632_image.png) -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/network_assets.md: -------------------------------------------------------------------------------- 1 | # Part 1: Network Assets 2 | 3 | In this tutorial you’ll learn how to create new Network Node Assets. 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | ## Video 8 | 9 | 10 | ## Tutorial 11 | In The Machinery, every simulation instance is separated from each other: the simulation that runs in the Simulate Tab, for example, is completely different from the simulation that runs on the Preview Tab, and they Cannot talk to each other: The goal of the Networking layer in The Machinery is to allow different Simulations to send data to each other. 12 | 13 | To do that, we introduced a specific type of asset that defines how a specific kind of simulation (Client, Server, Etc) should behave with regards to the other nodes that there are on the Network: The Network Node. 14 | 15 | To define a Network Node Asset, go in the asset browser, right click and select New→New Network Node. 16 | 17 | Let’s define a Server network Node and a Client Network Node so that we can use them in our project: 18 | 19 | ### Server 20 | 21 | We want the server to be able to receive packets from other nodes, so let’s bind the default Simulation Receiver interface in the Properties view. 22 | 23 | We also want our Server to Accept incoming connections from other Nodes. For now we’ll bind the “Accept From everyone” Accept interface, meaning that the server will accept connections from everyone. 24 | 25 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635338868858_image.png) 26 | 27 | ### Client 28 | 29 | Our Client will need to accept connections from the Server (In The Machinery the concept of “connection” is unilateral, so the Client will open a connection to the Server but in turn the Server will open a connection in the opposite direction) so let’s bind the “Accept from everyone” accept interface as well. 30 | 31 | The Client will also need to receive packets (the updates to the Gamestate that come from the Server), so make sure to bind the default simulation receiver to the Client as well. 32 | 33 | We want our Client to immediately connect to the Server when it’s started: let’s bind the “Connect to local Server” bootstrap interface. (It will run immediately after the Client instance is created) 34 | 35 | We also know that our Server will send Gamestate updates to our Client: so we want the Client to start with an empty world, assuming that all the necessary updates will later come from the Server. For this reason, make sure to toggle the “passive Gamestate” flag on the Client asset. 36 | 37 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635342631803_image.png) 38 | 39 | -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/smooth_animation.md: -------------------------------------------------------------------------------- 1 | # Part 6: Smooth Animation 2 | 3 | In this tutorial you’ll learn how to synchronize an animation across multiple simulation instances. This tutorial build on the learnings of the pervious tutorial: [Part 5]({{base_url}}/tutorials/network/animation_sample/basic_graph_variables.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | 8 | ## Video 9 | 10 | 11 | ## Tutorial 12 | 13 | Even if the orientation of each player is now correctly broadcasted, movement its not: we’d like to make it so each client receives the correct information about where each other client is moving, so that it can play the *animation* correctly. 14 | 15 | Take a look at the *WASD subgraph* section of the *xbot* entity: 16 | 17 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343896237_image.png) 18 | 19 | We want to inject some *float variable network replication* nodes on the float (green) connections to make it so that only the client that controls a specific player entity sets and replicates the movement variables: the value will be transmitted to the server, which will in turn broadcast it to all the other clients. (Exactly the same strategy we used for the facing direction). On the other hand, all the simulations running should *Get* the variable value (either from their own computation or from the network) and pass that value to the *Animation Set Variable* nodes. 20 | 21 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343687819_image.png) 22 | 23 | Important note: even if *Set if* is true in the *float variable network replication* node, the variable won’t actually be set if you don’t have control over that particular entity. Otherwise each simulation instance would override the variables of each other client as well as their own. 24 | 25 | Now all the player entities move smoothly on all the clients, and we added multiplayer support to the player movement code by just “hijacking” those four connections and injecting some network replication nodes in the middle of them. 26 | 27 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635344207286_image.png) -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/spawning_entities.md: -------------------------------------------------------------------------------- 1 | # Part 7: Spawning Entities 2 | 3 | In this tutorial you’ll learn how to Spawn an Entity with Prediction. This tutorial build on the learnings of the pervious tutorial: [Part 6]({{base_url}}/tutorials/network/animation_sample/smooth_animation.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | ## Video 8 | 9 | 10 | ## Tutorial 11 | 12 | Let’s see how we can trigger the spawning of an entity on the *server* by pressing a button on the *client.* 13 | 14 | First of all let’s make sure that the single player version of the spawning works: setup a single spawn entity node that is triggered when the P button is pressed. 15 | 16 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635344803694_image.png) 17 | 18 | Then go back to single player mode by just removing all the instances in the network settings and starting the simulation again, verifying that the entity is correctly spawned as the button is pressed. 19 | 20 | Now try to run a *client* and a *server* instance at the same time and try to press the button when the focus is on both window: 21 | 22 | -if you press the button while the client has focus, nothing will happen as the client has a *passive* gamestate and so even if the event is triggered the client won’t actually spawn any entity. 23 | 24 | -if the button is pressed while the server window is in focus, the entity will actually be spawned in the server simulation, and from then on its changes will be propagated to the other connected nodes. 25 | 26 | To fix this, let’s convert the *Poll key* node in a *Poll key for Entity* node: 27 | 28 | -If we now try to press the button while the focus is on the server nothing will happen, as the server is ignoring the local input for the player 29 | 30 | -pressing the button on the client will instead trigger the spawning event on the server (as the input is being replicated) 31 | 32 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635344875508_image.png) 33 | 34 | With the current setup, the client has to *wait* for its command to get to the server, be executed, and the entity state changes to come back before it can actually *see* the entity: if you were using this mechanism to spawn a projectile this would mean waiting potentially half a second or more before the player gets some feedback… definitively unacceptable. 35 | 36 | Let’s use the *spawn entity with prediction* to let the client create a local copy of the entity that has to be spawned, so that while the packets travel the internet, the client has already “predicted” the new entity creation locally. 37 | 38 | But before we can use that node we have to make sure that the *spawning* is done as a consequence of an event (as the event information is what’s used to do the “matching” between the local fake entity and the entity that will later come from the server). 39 | 40 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635344945502_image.png) 41 | 42 | Also, we’ll trigger the event only on the *client* and replicate the event itself via the *trigger event network replication* node: 43 | 44 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635345021091_image.png) 45 | 46 | We can now finally just convert our *spawn entity* node into a *spawn entity with prediction* node, and the client will correctly spawn (and later match) a fake entity on it’s own local simulation to give an immediate feedback to the player about what happened. 47 | 48 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635345050874_image.png) -------------------------------------------------------------------------------- /src/tutorials/network/animation_sample/support_multiple_players.md: -------------------------------------------------------------------------------- 1 | # Part 4: Supporting Multiple players 2 | 3 | In this tutorial you’ll learn how spawn an entity every time a client connects. This tutorial build on the learnings of the pervious tutorial: [Part 3]({{base_url}}/tutorials/network/animation_sample/entity_control.html) 4 | 5 | > **Note:** we start with making sure that you have the Networking feature flag enabled, you can do that in the **Tools→Feature Flags Menu**. 6 | 7 | ## Video 8 | 9 | 10 | ## Tutorial 11 | 12 | Let’s add support for multiple *Clients* to join the same world. 13 | 14 | Instead of referencing a static Entity in the scene, we now want to *spawn* a *new* xbot entity every time a client connects to the server: we can do that simply by converting the *Scene Entity* node into a *Spawn Entity* node. 15 | 16 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343132292_image.png) 17 | 18 | The other problem we need to solve to effectively support multiple players is the fact that earlier the Camera entity was itself available in the scene: know the camera entity is part of the dynamic entity that we’ll spawn once a client connects, and so the *Set Camera* node has to be executed inside the graph of the *xbot* entity asset itself, once the *Acquired Entity Control* event is triggered. 19 | 20 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343166633_image.png) 21 | 22 | And now our server fully supports multiple players to join: every time a Client connects to it, it will spawn a new *xbot* entity, set the control and remap the input of it: once the client is notified that it acquired the control of that entity, it will set the camera and remap the input as well. 23 | 24 | ![img](https://paper-attachments.dropbox.com/s_5F8ED61A9C68BDE8B9368D5E3DABD345E39CC324FB030EDE9E31314C3B7EE30F_1635343426333_image.png) -------------------------------------------------------------------------------- /src/tutorials/physics/README.md: -------------------------------------------------------------------------------- 1 | # Physics 2 | 3 | > You should read the [Physics Introduction]({{base_url}}/editing_workflows/physics.html) before you continue here. 4 | 5 | In this section we will discuss some of the Samples in more detail. 6 | 7 | You can download the Physics Sample projects from the Download Tab: **Help → Download Sample Projects** 8 | 9 | ![Where to find the samples](https://www.dropbox.com/s/1w81dsmhazf6pfn/tm_tut_physics_sample_download.png?raw=1) 10 | 11 | After you have downloaded the Physics Sample Project, you can open it: 12 | 13 | ![Where to find the scene](https://www.dropbox.com/s/igj4b4ao1ntb4zw/tm_tut_physics_scenes.png?raw=1) 14 | 15 | The `Scenes` folder contains all sample scenes (entities). Double click on a sample scene of your choice to load it. 16 | 17 | Each of the Sample Scenes is composed of multiple Entity Prototypes. You can find them in the `Special Objects` or in the `Shapes` folder: 18 | 19 | ![Special Objects folder](https://www.dropbox.com/s/cafrzpkal6sd1y7/tm_tut_physics_special_objects.png?raw=1) 20 | 21 | *Special Objects* are entities with Graph Components attached that have associated logic. 22 | 23 | ![](https://www.dropbox.com/s/og7wipthmw1hl7d/tm_tut_physics_shapes.png?raw=1) 24 | 25 | *Shapes* are reused Entities to demonstrate different kind of Physic Bodies. 26 | 27 | > **Note:** If you change the Prototypes, all the instances will change as well. Keep this in mind when playing around with the samples. If you mess things up, you can always re-download a fresh sample project. 28 | -------------------------------------------------------------------------------- /src/tutorials/physics/contacts.md: -------------------------------------------------------------------------------- 1 | # Contacts scene breakdown 2 | 3 | ![image-20220318094339252](https://www.dropbox.com/s/s2ocyt0bcywxjkl/image-20220318094339252.png?raw=1) 4 | 5 | ## Plane 6 | 7 | The Plane Entity is just a simple Entity with a Shape attached to it. 8 | 9 | 10 | 11 | ## Spawn Pile 12 | 13 | The Spawn Pile doesn't have any Physics component attached to it, but its Entity Graph will spawn a new Box every Three seconds and Push it down towards the Ground. 14 | 15 | ![image-20220317093117838](https://www.dropbox.com/s/pn0mnz7l1vcac8u/image-20220317093117838.png?raw=1) 16 | 17 | 18 | 19 | ## Ball thrower (Prototype location: Special Objects/Ball Thrower) 20 | 21 | The Ball Thrower doesn't have any Physics component either, but it will spawn a new ball in the viewing direction if the spacebar is pressed. The Logic is pretty similar to the one of the Spawn Pile: Spawn a new entity and use the Physx Push Node to push it in a specific direction, in this case the camera viewing direction. 22 | 23 | ![image-20220317093549002](https://www.dropbox.com/s/yxmcg9znvubo4jp/image-20220317093549002.png?raw=1) 24 | 25 | 26 | 27 | That's it for the Contacts scene, it's a pretty simple one. 28 | 29 | You will notice that the Boxes only collide with the blue spheres and the Ground plane: as an exercise try to make it so that the boxes also collides with each other. -------------------------------------------------------------------------------- /src/tutorials/physics/kinematic.md: -------------------------------------------------------------------------------- 1 | # Kinematic Scene breakdown 2 | 3 | ![image-20220317102629794](https://www.dropbox.com/s/jvy8da7ptkl5uk0/image-20220317102629794.png?raw=1) 4 | 5 | ## Plane 6 | 7 | Just static geometry like we saw in previous scenes. 8 | 9 | ## Walls 10 | 11 | Just static geometry. (Physics Shape component) 12 | 13 | ## Sweeper 14 | 15 | The sweeper is a simple rigid body with a rectangular shape that will perpetually rotate on it's own Y axis. 16 | 17 | The Rigid body component has the "Kinematic" flag set so that Physx knows that the position of the entity will be driven by its transform component. 18 | 19 | The Velocity component is used to apply (in this case) a constant angular velocity to the entity to make it rotate on its own axis. 20 | 21 | ![image-20220318094033356](https://www.dropbox.com/s/timq3uy7mfltzfp/image-20220318094033356.png?raw=1) 22 | 23 | ## Spawners 24 | 25 | There are four different spawners in the scene, placed at the four corners of the plane, and each one of them will spawn a physic object once every second. 26 | 27 | Notice that the spawned entities won't have any force applied to them, so they will just fall on the ground. (Until they get swept by the Sweeper, I mean) 28 | 29 | You can find the objects that will be spawned for each of the spawners under the Shapes folder. 30 | 31 | ![image-20220317102210569](https://www.dropbox.com/s/elydub9tniba8a7/image-20220317102210569.png?raw=1) 32 | 33 | ## Ball Thrower (Prototype location: Special Objects/Ball Thrower) 34 | 35 | The same ball thrower that we saw in the Contacts scene: press Space to throw a ball in the scene. 36 | -------------------------------------------------------------------------------- /src/tutorials/physics/stack.md: -------------------------------------------------------------------------------- 1 | # Stack Scene Breakdown 2 | 3 | ![image-20220317110041697](https://www.dropbox.com/s/hwqnbbewblkiifb/image-20220317110041697.png?raw=1) 4 | 5 | ## Plane 6 | 7 | Simple static geometry. 8 | 9 | 10 | 11 | ## Stack 12 | 13 | Simple static geometry. 14 | 15 | 16 | 17 | ## Ball Thrower 18 | 19 | Class Ball thrower that we already saw. 20 | 21 | 22 | 23 | ## Sniper 24 | 25 | The sniper will cast a ray into the scene using the `Physx Raycast` node if the Left mouse button is pressed and, if something is hit, it will push the hit entity in the camera direction. 26 | 27 | ![image-20220317110122631](https://www.dropbox.com/s/m02p85cft958l4q/image-20220317110122631.png?raw=1) 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/tutorials/the_truth/README.md: -------------------------------------------------------------------------------- 1 | ## Tutorials 2 | 3 | This section introduces you to some more complex topics such as [*How to Create your Own Asset Type*]({{base_url}}tutorials/the_truth/custom_asset/index.html). 4 | 5 | For more information checkout the [documentation]({{docs}}foundation/the_truth.h.html) and these blog posts 6 | 7 | * [The Story behind The Truth: Designing a Data Model](https://ourmachinery.com/post/the-story-behind-the-truth-designing-a-data-model/) 8 | * [Multi-Threading The Truth](https://ourmachinery.com/post/multi-threading-the-truth/). 9 | 10 | -------------------------------------------------------------------------------- /src/tutorials/the_truth/custom_asset/README.md: -------------------------------------------------------------------------------- 1 | # Creating a Custom Asset Type 2 | 3 | This walkthrough series shows you how to add a custom asset type to the Engine. You should have basic knowledge about how to write a custom plugin. If not, you might want to check this [Guide]({{base_url}}extending_the_machinery/the_plugin_system.html). The goal for this walkthrough is to create a text file asset type. 4 | 5 | We will cover the following topics: 6 | 7 | - [How to Create Your Asset Type]({{base_url}}/tutorials/the_truth/custom_asset/part1.html#creating-an-asset-the-truth-type) 8 | - [What is the Difference between a Truth Type and an Asset?]({{base_url}}/tutorials/the_truth/custom_asset/part1.html#what-is-the-difference-between-truth-type-and-asset) 9 | - [Add an Asset via Code to the Project]({{base_url}}/tutorials/the_truth/custom_asset/part1.html#appendix-adding-an-asset-via-code-to-the-asset-browser) 10 | - [How to Associate Data with Your Asset]({{base_url}}/tutorials/the_truth/custom_asset/part2.html#text-file-asset) 11 | - [How to Add a Custom UI to Your Asset]({{base_url}}/tutorials/the_truth/custom_asset/part2.html#custom-ui) 12 | - [How to Create Your Importer]({{base_url}}/tutorials/the_truth/custom_asset/part3.html#custom-importer-for-text-files) 13 | 14 | -------------------------------------------------------------------------------- /src/tutorials/ui/README.md: -------------------------------------------------------------------------------- 1 | # UI 2 | 3 | The Machinery's [UI system]({{docs}}plugins/ui/ui.h.html#ui.h), is a Immediate Mode GUI (IMGUI). Besides the information you can find here or in our API Documentation there are several Blog Posts you should check out: 4 | 5 | 6 | 7 | - [One Draw Call UI](https://ourmachinery.com/post/one-draw-call-ui/) 8 | - [UI rendering using Primitive Buffers](https://ourmachinery.com/post/ui-rendering-using-primitive-buffers/) 9 | - [Implementing drag-and-drop in an IMGUI](https://ourmachinery.com/post/implementing-drag-and-drop-in-an-imgui/) 10 | - [Localization in The Machinery’s UI](https://ourmachinery.com/post/localization-in-the-machinerys-ui/) 11 | 12 | -------------------------------------------------------------------------------- /src/tutorials/ui/build_custom_ui_controls/README.md: -------------------------------------------------------------------------------- 1 | # Build Custom UI Controls 2 | 3 | These walkthroughs we will teach you how to extend The Machinery's [UI system]({{docs}}/plugins/ui/ui.h.html#ui.h). 4 | 5 | 6 | 7 | In following following parts 1 - 3 we will cover the following topics: 8 | 9 | - [Create a custom circular button]({{base_url}}tutorials/ui/build_custom_ui_controls/part1.html) 10 | - [Add a texture to our custom control](#) 11 | - [Setup a UI Renderer](#) 12 | -------------------------------------------------------------------------------- /src/tutorials/ui/custom_layouts.md: -------------------------------------------------------------------------------- 1 | # Creating tab layouts through code 2 | 3 | The Machinery allows you to fully customize the editor layout. For personal layouts this system can be fully utilized without using code (see [Interface Customizations]({{base_url}}the_editor/customizations.html) for more information), but you might want to create custom default layouts that get defined procedurally, this allows for more control when loading and saving the layout. 4 | 5 | Creating layouts in code can be done though the `tm_tab_layout_api`. Here various functions are available for tab management. In this tutorial we’ll go over how the default workspace is created using the `save_layout` function. 6 | 7 | In order to create a layout for The Machinery editor we need access to the editor settings. This is done through `tm_the_machinery_api`. This tutorial uses the `tm_the_machinery_create_layout_i` interface in order to gain access to the settings. In these settings we have access to the window layouts, which is the subobject we want to append our layout to. The first things we should do however is check whether our layout already exists so we don’t create a new one every time on startup. 8 | 9 | ```c 10 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/ui/custom_layouts.c,create_layout)}} 11 | ``` 12 | 13 | After this we can start to define our actual tab layout. This is done through the `tm_tab_layout_t`. In this layout we can recursively define our tab layout with three distinct options per tabwell. 14 | 15 | - We can split the tabwell horizontally, creating top and bottom child tabwells. 16 | - We can split the tabwell vertically, creating left and right child tabwells. 17 | - We can define (up to 3) tabs that should be in this tabwell. 18 | ![](https://www.dropbox.com/s/ggiq4uv6htgwnpj/tm_tut_default_layout.png?raw=1) 19 | 20 | ```c 21 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/ui/custom_layouts.c,tm_tab_layout_t)}} 22 | ``` 23 | 24 | Defining the tabs is relatively straight forward, you define them using their name hash. Splitting a tabwell horizontally or vertically however requires a `bias` parameter. This defines the ratio of both tabs. Zero means both tabs are of equal size, whereas 1 means that the primary tab (left or top) fully encompass the tabwell whilst the secondary tab (right or bottom) is hidden. Negative values allow you to use the secondary tab as if it was the primary tab. 25 | 26 | ```c 27 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/ui/custom_layouts.c,register)}} 28 | ``` 29 | 30 | Finally we can store our layout in the application settings. The top level object for this is the 31 | window layout. This specified the default position and size of the window if the user decides the 32 | instantiate the layout in a new window rather than as a workspace. 33 | 34 | ## Entire Sample 35 | 36 | ```c 37 | {{insert_code(env.TM_BOOK_CODE_SNIPPETS/ui/custom_layouts.c)}} 38 | ``` 39 | -------------------------------------------------------------------------------- /src/writing_an_executable.md: -------------------------------------------------------------------------------- 1 | ## Writing an executable 2 | 3 | Writing a stand-alone executable is similar to writing a plugin except that you need to write 4 | initialization code for booting up all the systems that you want to use as well as the main loop 5 | code that runs the executable. 6 | 7 | `bin/simple-draw.exe` is a sample executable that uses the UI / Draw2D interfaces of The Machinery 8 | to implement a simple drawing program: 9 | 10 | ![Simple Draw executable.](https://www.dropbox.com/s/bilirde9yud4rn3/simple-draw.png?raw=1) 11 | 12 | The source code of this sample program is available in the `samples` directory. By playing with 13 | and modifying this, you can see how to build your own applications on top of *The Machinery*. 14 | 15 | Note that just as when writing plugins, you need a Visual Studio installation (2019) to build an 16 | executable. You need to set `TM_SDK_DIR` to the location of The Machinery SDK you are using, and you 17 | use `tmbuild.exe` to build the executable. 18 | 19 | `bin/simple-3d.exe` is a sample executable that uses the full 3D API. 20 | 21 | ![Simple 3D executable.](https://www.dropbox.com/s/oz9zob150yksnhr/simple-3d.png?raw=1) 22 | 23 | You will find the source code for this too in the samples directory. -------------------------------------------------------------------------------- /theme/head.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------