{"id":17543516,"url":"https://github.com/alixinne/glslt","last_synced_at":"2025-04-24T00:01:44.095Z","repository":{"id":57435020,"uuid":"275272978","full_name":"alixinne/glslt","owner":"alixinne","description":"GLSL Template compiler","archived":false,"fork":false,"pushed_at":"2025-04-21T23:21:45.000Z","size":3812,"stargazers_count":8,"open_issues_count":3,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-22T00:25:22.280Z","etag":null,"topics":["glsl","lambda-expression","rust"],"latest_commit_sha":null,"homepage":"https://alixinne.github.io/glslt/glslt/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alixinne.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-06-27T00:38:44.000Z","updated_at":"2024-11-11T09:40:25.000Z","dependencies_parsed_at":"2023-10-12T14:56:32.076Z","dependency_job_id":"6b6bf832-e18f-45a6-a0d1-d7eb1ba44b86","html_url":"https://github.com/alixinne/glslt","commit_stats":{"total_commits":168,"total_committers":3,"mean_commits":56.0,"dds":"0.059523809523809534","last_synced_commit":"420099e509ed5b1438da4d12f5e6f54d8ed7ceed"},"previous_names":["alixinne/glslt","vtavernier/glslt"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alixinne%2Fglslt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alixinne%2Fglslt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alixinne%2Fglslt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alixinne%2Fglslt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alixinne","download_url":"https://codeload.github.com/alixinne/glslt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250156392,"owners_count":21384123,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["glsl","lambda-expression","rust"],"created_at":"2024-10-21T00:24:30.996Z","updated_at":"2025-04-24T00:01:43.068Z","avatar_url":"https://github.com/alixinne.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# [glslt](https://github.com/alixinne/glslt)\n\n[![Run tests](https://github.com/alixinne/glslt/workflows/Run%20tests/badge.svg?branch=master)](https://github.com/alixinne/glslt/actions) [![GitHub release](https://img.shields.io/github/v/release/alixinne/glslt)](https://github.com/alixinne/glslt/releases) [![PyPI](https://img.shields.io/pypi/v/glslt)](https://pypi.org/project/glslt/) [![License](https://img.shields.io/github/license/alixinne/glslt)](LICENSE)\n\n`glslt` is a prototype language for adding template functions to the GLSL\nlanguage.\n\nAlthough they are not strictly needed for basic shading operations, they are of\nparticular interest for designing reusable GLSL components which agree on\ncommon interfaces, as function pointers (or callbacks) would provide.\n\n## Table of contents\n\n\u003c!-- vim-markdown-toc GFM --\u003e\n\n* [Installation](#installation)\n* [Usage](#usage)\n    * [Static template function parameters](#static-template-function-parameters)\n    * [Lambda template function parameters](#lambda-template-function-parameters)\n        * [Named placeholders](#named-placeholders)\n    * [Nested lambda expressions](#nested-lambda-expressions)\n    * [Support for include directives](#support-for-include-directives)\n    * [Minifying mode](#minifying-mode)\n* [Features](#features)\n* [Bindings](#bindings)\n    * [Rust](#rust)\n    * [Python](#python)\n* [Limitations](#limitations)\n* [Author](#author)\n\n\u003c!-- vim-markdown-toc --\u003e\n\n## Installation\n\nCheck out the [releases](https://github.com/alixinne/glslt/releases) for\npre-compiled binaries for stable versions. Installing the Python module (see\nbelow) also installs the corresponding `glsltc` binary.\n\nAlternatively, you may compile `glslt` from source, assuming you have the\n[Rust](https://rustup.rs/) compiler installed:\n\n```bash\n# From crates.io\ncargo install --force glslt_cli\n\n# From the repository\n## Fetch the source\ngit clone https://github.com/alixinne/glslt.git\ncd glslt\n\n## Run the program directly\ncargo run -- test.glsl\n\n## Or, install the glsltc binary permanently\ncargo install --force --path .\nglsltc test.glsl\n```\n\nTo install the Python module for the latest stable version, you can use `pip`:\n\n```bash\npip install glslt\n```\n\nIf you downloaded the source and want to build the latest version of the Python\nmodule, use `maturin`:\n\n```bash\n# Install maturin (only needed once)\npip install maturin==0.13.6\n\n# Assuming you are in a virtualenv\n(cd glslt \u0026\u0026 maturin develop --features python -b pyo3)\n```\n\n## Usage\n\n### Static template function parameters\n\n`glslt` supports *static template function parameters*. This means, passing the\nname of an already-declared function as a parameter for a templated function.\nHere is an example:\n\n```glsl\n#version 460 core\n\n// A pointer to a function that has no args and returns an int\n//\n// We use function prototypes for this matter since they're\n// basically useless in GLSL. Since there can be no indirect\n// recursion, there is no need for function pre-declarations.\nint intfn();\n\n// A first function that could be an intfn\nint fnReturnsOne() { return 1; }\n\n// A second function that could be an intfn\nint fnReturnsTwo() { return 2; }\n\n// A template function. It's recognized as a template because it uses intfn\n// which has been declared as a function pointer.\n//\n// In the generated code, there will be no function called fnTemplate, as all\n// calls to fnTemplate will be replaced with template specializations.\n//\n// Thus, callback can only be an identifier of an existing function, which\n// should (later: must with type-checking) match the pointer type\nint fnTemplate(in intfn callback) { return callback(); }\n\nvoid main() {\n    // Calling fnTemplate with function pointers\n    gl_FragColor =\n        vec4(fnTemplate(fnReturnsOne), fnTemplate(fnReturnsTwo), 0., 1.);\n}\n```\n\nNote that we do not define a new syntax. Instead, we use the function\npre-declaration syntax which is rarely used to declare function pointers. Thus,\nall your existing tooling still works with `glslt`.\n\nIn order to run this code on your GPU, you need to process it so function\ntemplates are *instantiated* with their actual template parameters. This is\nwhere this tool comes in:\n\n```bash\n# Assuming you installed the pre-built glsltc binary, if running from source use `cargo run --` instead.\n#\n# test.glsl is our input example, output.glsl is the generated code.\nglsltc -o output.glsl test.glsl\n```\n\nThe resulting code will look like this:\n\n```glsl\n#version 460 core\nint fnReturnsOne() {\n    return 1;\n}\n\nint fnReturnsTwo() {\n    return 2;\n}\n\nint _glslt_fnTemplate_dd5173() {\n    return fnReturnsOne();\n}\n\nint _glslt_fnTemplate_4314fd() {\n    return fnReturnsTwo();\n}\n\nvoid main() {\n    gl_FragColor = vec4(_glslt_fnTemplate_dd5173(), _glslt_fnTemplate_4314fd(), 0., 1.);\n}\n```\n\nNote how the template function calls have been replaced by regular GLSL\nfunctions. This code can be directly used in an OpenGL application.\n\n### Lambda template function parameters\n\n`glslt` also supports *lambda template function parameters*. Instead of passing\na function name as a parameter to the templated function, you may pass an\nexpression. This expression may capture local variables and parameters, which\nwill be taken into account when instantiating the template. Here is an example:\n\n```glsl\nfloat sdf3d(in vec3 p);\n\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\nfloat opElongate(in sdf3d primitive, in vec3 p, in vec3 h) {\n    vec3 q = p - clamp(p, -h, h);\n    return primitive(q);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    fragColor = vec4(vec3(opElongate(sdSphere(_1, 4.), vec3(fragCoord, 0.), vec3(1., 2., 3.))), 1.0);\n}\n```\n\nNote how instead of just passing `sdSphere` as a template parameter, we pass\n`sdSphere(_1, 4.)`. This translates to calling `sdSphere` with the first\nparameter given by the template function `opElongate`, while the second\nparameter is the constant `4.`. This results in the following code:\n\n```glsl\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\nfloat _glslt_opElongate_d20939(in vec3 p, in vec3 h) {\n    vec3 q = p - clamp(p, -h, h);\n    return sdSphere(q, 4.);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    fragColor = vec4(vec3(_glslt_opElongate_d20939(vec3(fragCoord, 0.), vec3(1., 2., 3.))), 1.);\n}\n```\n\nSince captures are supported, this example may have been written with the\nsphere diameter being a parameter:\n\n```glsl\nfloat sdf3d(in vec3 p);\n\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\nfloat opElongate(in sdf3d primitive, in vec3 p, in vec3 h) {\n    vec3 q = p - clamp(p, -h, h);\n    return primitive(q);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    float sz = 5.;\n    fragColor = vec4(vec3(opElongate(sdSphere(_1, sz), vec3(fragCoord, 0.), vec3(1., 2., 3.))), 1.0);\n    //                                            ^^\n    // Using a local variable in the template argument\n}\n```\n\nThe variable is properly captured in the generated code:\n\n```glsl\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\n// _glslt_lp2 is the captured variable input\nfloat _glslt_opElongate_d9170f(in vec3 p, in vec3 h, float _glslt_lp2) {\n    vec3 q = p - clamp(p, -h, h);\n    return sdSphere(q, _glslt_lp2);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    float sz = 5.;\n    fragColor = vec4(vec3(_glslt_opElongate_d9170f(vec3(fragCoord, 0.), vec3(1., 2., 3.), sz)), 1.);\n    //                                                                 Captured variable: ^^\n}\n```\n\n#### Named placeholders\n\nWhen passing a lambda expression to a template function, you may use the\nunnamed placeholders `_1`, `_2`, etc. to refer to the first, second, etc.\narguments to the template function call. You may also use the parameter names\nas declared in the function prototype. The previous example could be written as\nfollows:\n\n```glsl\n// In sdf3d template parameters, `p` is the first parameter name\nfloat sdf3d(in vec3 p);\n\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\nfloat opElongate(in sdf3d primitive, in vec3 p, in vec3 h) {\n    vec3 q = p - clamp(p, -h, h);\n    return primitive(q);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    fragColor = vec4(vec3(opElongate(sdSphere(_p, 1.0), vec3(fragCoord, 0.), vec3(1., 2., 3.))), 1.0);\n    //                                        ^^\n    // Named placeholder parameter in a template instead of _1\n}\n```\n\nThe generated code will look like this:\n\n```glsl\nfloat sdSphere(vec3 p, float r) {\n    return length(p) - r;\n}\n\nfloat _glslt_opElongate_784a47(in vec3 p, in vec3 h) {\n    vec3 q = p - clamp(p, -h, h);\n    return sdSphere(q, 1.);\n}\n\nvoid mainImage(out vec4 fragColor, in vec2 fragCoord) {\n    fragColor = vec4(vec3(_glslt_opElongate_784a47(vec3(fragCoord, 0.), vec3(1., 2., 3.))), 1.);\n}\n```\n\n### Nested lambda expressions\n\nNested lambda expressions are supported, however due to the syntax being used,\nwe have to make a decision on how to resolve the anonymous placeholders to\ntheir corresponding lambda. The current algorithm transforms innermost lambdas\nfirst, so the placeholders will resolve to the most nested expression first.\n\nThis may be circumvented by using named placeholders (as long as there is no\nconflict) since undefined identifiers are passed as-is to the other passes of\nthe transformation algorithm, and thus, to outer lambdas.\n\n### Support for include directives\n\n`#include` directives are supported and will be processed, using the same rules\nas C preprocessors: double-quoted paths will be looked up from the current file\nbeing parsed. Angle-quoted paths will be looked up from the system include\npaths.\n\n### Minifying mode\n\nIn its default mode, the GLSLT compiler will copy all input declarations to its\noutput (except function prototypes) and insert instantiated templates right\nbefore they are used.\n\nHowever, if you are using the GLSLT compiler with a large template library,\nthis will generate a lot of unused code. By using the `-K, --keep-fns` argument\nto the `glsltc` command, GLSLT switches to the minifying mode. In this mode,\nonly the functions, types, and globals that are transitive dependencies of the\nfunctions specified by the `-K` argument are kept.\n\n`#version`, `#extension` and precision specifiers will be included at the top\nof the generated code, if they were present in the input.\n\nAs an example, compiling the previous example with `glsltc -K=sdSphere` will\nonly return the code for the sdSphere function, since it has no dependencies.\n\n## Features\n\n- [x] Include support\n- [ ] Preserve comments in original source\n- [ ] Report position in compiler errors\n- [x] Lambda template function parameters\n- [x] Static template function parameters\n\n## Bindings\n\n### Rust\n\nSince this tool is developed in Rust, the *native* bindings are exposed as the\n`glslt` Rust crate and can be used directly by client code.\n\n### Python\n\nThe main library exposes a native Python 3 module using\n[pyo3](https://pyo3.rs/). Use [maturin](https://github.com/PyO3/maturin) to\nbuild and develop the Python module, inside a virtualenv.\n\nIn order to build the Python package, you have to enable the `python` feature\nand have `python3-dev` installed. See the documentation for [glslt](glslt/) for\nan example.\n\n## Limitations\n\nThis program is based on the [glsl-lang](https://github.com/alixinne/glsl-lang)\ncrate for parsing and manipulating the GLSL AST in Rust. However, since it's\nonly an AST and not a full parse tree, we have currently no way of preserving\noriginal formatting. Comments are still parsed and are available to library\nusers, but they are not currently included in the output.\n\n## Author\n\nAlixinne \u003calixinne@pm.me\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falixinne%2Fglslt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falixinne%2Fglslt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falixinne%2Fglslt/lists"}