{"id":13482437,"url":"https://github.com/saharan/HGSL","last_synced_at":"2025-03-27T13:31:50.321Z","repository":{"id":148312789,"uuid":"480005377","full_name":"saharan/HGSL","owner":"saharan","description":"A shading language that can be compiled into GLSL ES 3.0","archived":false,"fork":false,"pushed_at":"2023-11-19T11:42:49.000Z","size":652,"stargazers_count":139,"open_issues_count":3,"forks_count":2,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-08-01T17:32:18.677Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haxe","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/saharan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2022-04-10T12:05:28.000Z","updated_at":"2024-07-18T14:23:38.000Z","dependencies_parsed_at":"2024-01-03T03:54:16.987Z","dependency_job_id":"25fff997-1fef-45ad-bae7-dcbc9a45573e","html_url":"https://github.com/saharan/HGSL","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saharan%2FHGSL","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saharan%2FHGSL/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saharan%2FHGSL/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/saharan%2FHGSL/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/saharan","download_url":"https://codeload.github.com/saharan/HGSL/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":222262256,"owners_count":16957539,"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":[],"created_at":"2024-07-31T17:01:01.989Z","updated_at":"2024-10-30T16:30:54.326Z","avatar_url":"https://github.com/saharan.png","language":"Haxe","readme":"# HGSL: Haxe to GL Shading Language\n\n## What is this?\n\nThis library enables you to write GLSL ES 3.0 programs (especially for WebGL 2.0) with the full help of an IDE, including any kinds of completions and type checks.\n\nYou can also use features that are not included in GLSL ES 3.0: implicit type conversions, modularization of common logic and constants, inheritances, anonymous structures, and many other things.\n\nEverything is done at compile time, so you can use this library just to obtain GLSL source codes, or you can integrate shader classes into your project if it uses Haxe.\n\n## Getting started\n\n1. Install [Haxe](https://haxe.org/) 4.3.1 or later somewhere\n1. Install [vshaxe](https://github.com/vshaxe/vshaxe) in VSCode Marketplace and configure the Haxe path\n1. Create a Haxe project (`\u003eHaxe: Initialize Project`)\n1. Copy `src/hgsl` to your source folder\n\t- or install HGSL using [Haxelib](https://lib.haxe.org/) by `haxelib install hgsl`\n1. Write your shaders!\n\n## How to use\n\n### Introduction\n\nImport `hgsl.Global.*` for built-in functions and variables, `hgsl.Types` for built-in types. Note that importing `hgsl.Types` hides standard types (`Int`, `UInt`, `Float`, `Bool`, `Array`), so make sure not to import it in any non-shader source files.\n\nA main shader class should extend `hgsl.ShaderMain`, and implement entry-point functions for both vertex and fragment shader.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nclass Shader extends ShaderMain {\n\tfunction vertex():Void { // vertex shader entrypoint\n\t}\n\n\tfunction fragment():Void { // fragment shader entrypoint\n\t}\n}\n```\n\n- Define vertex attributes using `@attribute` metadata. You can also specify layout location by `@attribute(\u003clocation\u003e)`.\n- Define uniforms using `@uniform` metadata. Defined uniforms can be used from both vertex shader part and fragment shader part.\n- Define varyings using `@varying` metadata. You can specify types of varyings by `@varying(flat)` and `@varying(centroid)`.\n- Define output colors using `@color` metadata. MRT (Multiple Render Targets) is available by setting location with `@color(\u003clocation\u003e)`.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nclass Shader extends ShaderMain {\n\t@attribute(0) var position:Vec4;\n\t@attribute(1) var color:Vec4;\n\t@attribute(2) var texCoord:Vec2;\n\n\t@uniform var transform:Mat4;\n\t@uniform var colorTexture:Sampler2D;\n\n\t@varying var vcolor:Vec4;\n\t@varying(centroid) var vtexCoord:Vec2;\n\n\t@color var ocolor:Vec4;\n\n\tfunction vertex():Void { // vertex shader entrypoint\n\t\tgl_Position = transform * position; // built-in output position\n\t\tvcolor = color;\n\t\tvtexCoord = texCoord;\n\t}\n\n\tfunction fragment():Void { // fragment shader entrypoint\n\t\tocolor = vcolor * texture(colorTexture, vtexCoord);\n\t}\n}\n```\n\n### Modules\n\nYou can define a shader module that contains compile-time constants and functions by extending `hgsl.ShaderModule` class.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\nimport hgsl.ShaderMain;\n\nclass Module extends ShaderModule {\n\tfinal SOME_CONST_NUMBER:Int = 16;\n\tfinal SOME_CONST_VECTOR:Vec3 = vec3(1, 2, 3); // you can use type constructors\n\tfinal ANOTHER_CONST_NUMBER:Float = SOME_CONST_NUMBER * 2.0; // you can refer another const\n\t// final SIN1:Float = sin(1); // ERROR! built-in functions are not compile-time constant\n\n\tfunction someUtility(input:Vec3):Vec3 { // you can use this function from outside the module\n\t\tvar output:Vec3 = input * 2;\n\t\treturn output;\n\t}\n}\n\nclass Shader extends ShaderMain {\n\tfunction vertex():Void {\n\t\tModule.SOME_CONST_NUMBER; // use consts\n\t\tvar foo:Vec3 = Module.someUtility(vec3(1, 2, 3)); // and functions\n\t}\n\n\tfunction fragment():Void {\n\t}\n}\n```\n\n### Automatic Typing\n\nAs long as a variable definition has an initial value, the type specification of the variable can be omitted.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfinal INT_CONST = 16; // int\n\tfinal FLOAT_CONST = 8.0; // float\n\tfinal VEC3_CONST = vec3(1, 2, 3); // vec3\n\n\tfunction func():Void {\n\t\tvar nonConstMatrix = mat3(1); // mat3x3, also available\n\t\t                              //   for non-const variables\n\t\t// var foo; // ERROR! variable declaration without\n\t\t            //   both initial value and type is illegal\n\t}\n\n\t// function func2(a, b, c) { // ERROR! return type and\n\t// }                         //   argument types cannot be omitted\n}\n```\n\n### `var` and `final`\n\n`var` and `final` can be both used to declare a variable, but there are differences.\n\n- `var` can be used to declare a **mutable** variable\n- `final` can be used to declare an **immutable** variable\n  - A `final` variable is NOT necessarily a compile-time constant\n  - If a `final` variable is initialized with a compile-time constant value, then it becomes a **compile-time constant**\n  - You cannot use `final` to define a field of a structure\n\n### Structures\n\nYou can define a named structure by making a class that extends `hgsl.ShaderStruct`.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderStruct;\n\nclass Struct extends ShaderStruct {\n\tvar fieldA:Int;\n\tvar fieldB:Vec3;\n\tvar fieldC:Mat3x3;\n}\n```\n\nStructures can be nested, but no circular reference is allowed.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderStruct;\n\nclass Struct2 extends ShaderStruct {\n\tvar nestedStruct:Struct;\n\t// var ng:Struct2; // ERROR! infinite recursion occurs\n}\n\nclass Struct extends ShaderStruct {\n\tvar fieldA:Int;\n\tvar fieldB:Vec3;\n\tvar fieldC:Mat3x3;\n\t// var ng:Struct2; // ERROR! this also creates an infinite loop\n}\n```\n\nAnonymous structures can also be used everywhere.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderStruct;\nimport hgsl.ShaderModule;\n\nclass Struct extends ShaderStruct {\n\tvar fieldA:Int;\n\tvar fieldB:Vec3;\n\tvar fieldC:{\n\t\tvar some:Vec2;\n\t\tvar nested:{\n\t\t\tvar fields:Float;\n\t\t}\n\t}\n}\n\nclass Module extends ShaderModule {\n\tfunction func(arg:{a:Int, b:Float}):{a:Int, b:Float} {\n\t\targ.a++;\n\t\treturn arg;\n\t}\n}\n\n```\n\nIn fact, named structures are just type alias or syntax sugar of anonymous structures.\n\n### Arrays\n\nUse `Array\u003cType, Size\u003e` to refer an array type. Every array must be given a compile-time constant size.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderStruct;\nimport hgsl.ShaderModule;\n\nclass Struct extends ShaderStruct {\n\tvar floats:Array\u003cFloat, 8\u003e;\n\tvar vec3s:Array\u003cVec3, 4\u003e;\n\tvar mat4s:Array\u003cMat4, Module.LENGTH\u003e;  // you can refer external values\n\t// var ints:Array\u003cInt, Module.length\u003e; // ERROR! fields start with a\n\t                                       // lower-case alphabet cannot be used\n}\n\nclass Module extends ShaderModule {\n\tfinal LENGTH = 32;\n\tfinal length = LENGTH; // ... even though it IS a compile-time constant :(\n}\n```\n\nLimitation: due to the Haxe's grammar, you cannot use a field starts with a lower-case alphabet for an array size parameter, even if it is actually a compile-time constant.\n\n### Literal arrays and structures\n\nYou can use literal arrays and structures to generate a value of an array or structure. There is **no constructor** for them.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderStruct;\nimport hgsl.ShaderModule;\n\nclass Struct extends ShaderStruct {\n\tvar ints:Array\u003cInt, 3\u003e;\n\tvar floats:Array\u003cFloat, 5\u003e;\n\tvar structs:Array\u003c{\n\t\ta:Int,\n\t\tb:Int\n\t}, 2\u003e;\n}\n\nclass Module extends ShaderModule {\n\tfinal CONST_STRUCT:Struct = {\n\t\tints: [1, 2, 3],\n\t\tfloats: [1.0, 2.0, 3.0, 4.0, 5.0],\n\t\tstructs: [{a: 1, b: 2}, {a: 3, b: 4}]\n\t} // this is a compile-time constant\n}\n```\n\nA literal array that consists only of compile-time constants will also be a compile-time constant value. Likewise, a literal structure that consists only of compile-time constant fields will also be a compile-time constant value.\n\nIf a certain type is **expected**, elements of a literal array will be implicitly converted.\n\n```hx\nvar a = [1, 2, 3, 4, 5];                 // int[5]\nvar b:Array\u003cFloat, 5\u003e = [1, 2, 3, 4, 5]; // float[5], since floats are expected\n// a = b; // ERROR! cannot assign one to the other,\n// b = a; // ERROR!   since Array is parameter invariant\n```\n\nIf there is no expected type, the first element of an array will determine the expected type for the rest of the elements.\n\n```hx\nvar a = [1.0, 2, 3, 4, 5];          // float[5]\nvar b = [uint(1), 2, 3, 4, 5];      // uint[5]\n// var c = [1, 2.0, 3.0, 4.0, 5.0]; // ERROR! cannot convert floats to ints\n```\n\nThis \"expected type\" rule also applies for structures.\n\n```hx\nvar a:{x:Array\u003cFloat, 5\u003e, y:UInt} = {\n\tx: [1, 2, 3, 4, 5], // float[5], since floats are expected\n\ty: 1                // uint, since uint is expected\n}\nvar b = {\n\tx: [1, 2, 3, 4, 5], // int[5]\n\ty: 1                // int\n}\n// a = b; // ERROR! types are different\n```\n\nUnlike some other languages (including Haxe), the order of fields in a structure matters.\n\n```hx\nvar a = {x: 1, y: 1}\nvar b = {y: 1, x: 1}\n// a = b; // ERROR! types of these variables are different\n```\n\nThis is mainly because the actual data on memory vary depending on the order of the fields, and there should be a way for users to determine the order of the fields (especially for uniform variables).\n\n### Inheritance\n\nYou can inherit a shader to make its variances.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nclass Shader extends ShaderMain {\n\tfunction foo():Int {\n\t\treturn 1;\n\t}\n\n\tfunction vertex():Void {\n\t\tfoo(); // 1\n\t}\n\n\tfunction fragment():Void {\n\t}\n}\n\nclass ChildShader extends Shader {\n\tfunction foo():Int { // override! make it return 2\n\t\treturn 2;\n\t}\n}\n```\n\nIn the original shader (`Shader`), `1` is computed in the vertex part. However, since the function `foo` is overridden in the child shader(`ChildShader`), `2` is computed in the vertex part of the shader. Note that you do NOT need `override` qualifier to override a function.\n\n```hx\nclass ChildShader extends Shader {\n\tfunction foo():Int { // override! increase the value by one\n\t\treturn super.foo() + 1;\n\t}\n}\n```\n\nYou can refer parent implementations by using the keyword `super`. In this case, the result is the same as the previous one (returns `2`).\n\nAll variables will be inherited and cannot be overridden.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\n// a very simple shader\nclass Shader extends ShaderMain {\n\t@uniform var transform:Mat4;\n\t@attribute var aPos:Vec4;\n\t@attribute var aColor:Vec4;\n\t@varying var color:Vec4;\n\t@color var oColor:Vec4;\n\n\tfunction vertex():Void {\n\t\tgl_Position = transform * aPos;\n\t\tcolor = aColor;\n\t}\n\n\tfunction fragment():Void {\n\t\toColor = color;\n\t}\n}\n\n// also a simple shader but with texturing\nclass ChildShader extends Shader {\n\t// add various fields to make it support texturing\n\t@uniform var tex:Sampler2D;\n\t@attribute var aTexCoord:Vec2;\n\t@varying(centroid) var texCoord:Vec2;\n\n\tfunction vertex():Void {\n\t\tsuper.vertex();\n\t\ttexCoord = aTexCoord; // output texCoord as well\n\t}\n\n\tfunction fragment():Void {\n\t\toColor = color * texture(tex, texCoord);\n\t}\n}\n```\n\n### Overload\n\nOverload of functions is done just like as in GLSL ES 3.0 (and many other languages). You do NOT need to use `overload` qualifier to overload functions.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func(a:Int,   b:Int  ):Int { return 1; }\n\tfunction func(a:UInt,  b:Float):Int { return 2; }\n\tfunction func(a:Float, b:UInt ):Int { return 3; }\n\tfunction func(a:Float, b:Float):Int { return 4; }\n\t\n\tfunction func():Void {\n\t\tvar i:Int, u:UInt, f:Float;\n\t\tfunc(i, i); // 1, exact match\n\t\tfunc(u, f); // 2\n\t\tfunc(f, u); // 3\n\t\tfunc(f, f); // 4\n\t\t\n\t\tfunc(i, f); // 2, not exact but matches \"best\"\n\t\tfunc(f, i); // 3\n\t\t\n\t\t// func(u, u); // ERROR! cannot determine which one is the \"best\"\n\t}\n}\n```\n\n### Higher-Order Functions\n\nYou can define higher order functions. You can pass functions to another function. Also, you can bind a function to a compile-time constant (always use `final` keyword).\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func(f:(a:Int, b:Int) -\u003e Int):Int { // receive a function\n\t\treturn f(1, 2);\n\t}\n\t\n\tfunction add(a:Int, b:Int):Int {\n\t\treturn a + b;\n\t}\n\t\n\tfunction passFunc():Void {\n\t\tfinal f = add; // bind a function as a compile-time constant\n\t\tfunc(f); // pass the function\n\t\tfunc(add); // or do it directly\n\t}\n}\n```\n\nThere are several ways to represent the type of a function.\n\n```hx\nfinal fpLike:   Int -\u003e Int -\u003e Int = Module.add; // receives Int and Int, returns Int\nfinal named:(a:Int, b:Int) -\u003e Int = Module.add; // the same, but with names\n\nfinal higherOrder:           (Int -\u003e Int -\u003e Int) -\u003e Int = Module.func;\nfinal higherOrderNamed:(f:(a:Int, b:Int) -\u003e Int) -\u003e Int = Module.func;\n\nfinal noArgs:Void -\u003e Void = Module.passFunc;\nfinal noArgs2: () -\u003e Void = Module.passFunc; // more consistent with named ones\n```\n\nYou can define local functions and capture local variables by reference.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func():Void {\n\t\tvar a = 1;\n\t\tfunction localFunc():Void {\n\t\t\t final b = 2;\n\t\t\t a + b; // 3\n\t\t\t a *= 10;\n\t\t\t a + b; // 12\n\t\t}\n\t\tlocalFunc();\n\t\ta; // 10\n\t}\n}\n```\n\nYou can return a local function. When it is done, **a closure** will be generated.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func():() -\u003e (() -\u003e Int) {\n\t\tvar a = 0;\n\t\tfunction increment():Int {\n\t\t\treturn ++a;\n\t\t}\n\t\treturn increment; // return a local function\n\t}\n\t\n\tfunction useClosure():Void {\n\t\tfinal c1 = func(); // a closure is generated\n\t\tc1(); // 1\n\t\tc1(); // 2\n\t\tc1(); // 3\n\t\t\n\t\tfinal c2 = func(); // another closure is generated\n\t\tc2(); // 1\n\t\tc2(); // 2\n\t\t\n\t\tc1(); // 4; every closure will keep its own environment\n\t}\n}\n```\n\nYou can use the arrow notation to generate an anonymous function.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func():Void {\n\t\tvar a = 0;\n\t\tfinal increment = () -\u003e ++a;        // equivalent\n\t\tfinal increment2 = function():Int { // equivalent\n\t\t\treturn ++a;\n\t\t}\n\t\tfinal addTyped = (a:Int, b:Int) -\u003e a + b; // arguments are explicitly typed\n\t\tfinal add:Int -\u003e Int -\u003e Int = (a, b) -\u003e a + b; // \"expected type\" helps the type inference\n\t\t// final add = (a, b) -\u003e a + b; // ERROR! argument types are unknown\n\t}\n}\n```\n\nFunctions can be implicitly converted according to their argument types and return types.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Module extends ShaderModule {\n\tfunction func():Void {\n\t\tfinal float2float:Float -\u003e Float = a -\u003e a;\n\t\tfinal float2void:Float -\u003e Void = float2float; // safe: discard the return value\n\t\tfinal int2float:Int -\u003e Float = float2float;   // safe: implicitly convert the argument\n\t\t// final float2int:Int -\u003e Int = float2float;  // ERROR! implicit conversion from float\n\t\t                                              //   to int cannot be done\n\t}\n}\n```\n\n### Obtain Shader Source\n\nYou can obtain source code of shaders using `vertexSource` and `fragmentSource` fields, or `vertex` and `fragment` fields inside `source` field. These fields can only be used from outside shaders.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nimport hgsl.Source;\n\nclass Shader extends ShaderMain {\n\t...\n}\n\nclass Main { // this is NOT a shader class; usual Haxe rules apply here\n\tstatic function main() {\n\t\t// print the source, or do whatever you need; they are just strings\n\t\ttrace(Shader.vertexSource);\n\t\ttrace(Shader.fragmentSource);\n\t\t\n\t\t// extract source out of the shader, this is convenient\n\t\t//   when you have to treat multiple shaders\n\t\tfinal source:Source = Shader.source;\n\t\ttrace(source.vertex);\n\t\ttrace(source.fragment);\n\t}\n}\n```\n\nYou can also access vertex attributes and uniforms through `attributes` and `uniforms` fields, respectively. If you only want to access attribute locations or uniform names, you can also use `a` or `u` field, respectively.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nimport hgsl.Attribute;\nimport hgsl.Uniform;\n\nclass Shader extends ShaderMain {\n\t@uniform var transform:Mat4;\n\t@attribute var aPos:Vec4;\n\t...\n}\n\nclass Main {\n\tstatic function main() {\n\t\t// print attribute information\n\t\tfinal aPos:Attribute = Shader.attributes.aPos;\n\t\ttrace(aPos.name);     // \"aPos\"\n\t\ttrace(aPos.type);     // Vec(4) in `AttributeType`\n\t\ttrace(aPos.location); // null, since no location is given\n\t\ttrace(Shader.a.aPos); // null, equals `aPos.location`\n\t\t\n\t\t// print uniform information\n\t\tfinal transform:Uniform = Shader.uniform.transform;\n\t\ttrace(transform.name);     // \"transform\"\n\t\ttrace(transform.type);     // Mat(4, 4) in `UniformType`\n\t\ttrace(Shader.u.transform); // \"transform\", equals `transform.name`\n\t}\n}\n```\n\nNote that these fields are **statically typed**, which means if you change the names of variables in the shader class and leave the main class as it is, there will be errors.\n\n```hx\nimport hgsl.Global.*;\nimport hgsl.Types;\nimport hgsl.ShaderMain;\n\nclass Shader extends ShaderMain {\n\t@uniform var transformModified:Mat4; // modify\n\t@attribute var aPosModified:Vec4;    //   their names\n\t...\n}\n\nclass Main {\n\tstatic function main() {\n\t\t// trace(Shader.attributes.aPos);   // ERROR! no such field\n\t\t// trace(Shader.uniform.transform); // ERROR! no such field too\n\t}\n}\n```\n\nCompile-time constants in a shader can be accessed from outside shaders ONLY through `consts` or `c` field.\n\n```hx\nimport hgsl.Types;\nimport hgsl.ShaderModule;\n\nclass Shader extends ShaderMain {\n\tfinal SOME_CONST_STRUCT = {x: 1, y: 2};\n}\n\nclass Module extends ShaderModule {\n\tfinal SOME_CONST_INT = 8;\n\tfinal SOME_CONST_ARRAY = [1, 2, 3];\n}\n\nclass Main { // usual Haxe class\n\tstatic function main() {\n\t\t// value of StdTypes.Int (not hgsl.Types.Int)\n\t\ttrace(Module.consts.SOME_CONST_INT);\n\t\t\n\t\t// value of std.Array\u003cStdTypes.Int\u003e (not hgsl.Types.Array\u003cInt, 3\u003e)\n\t\ttrace(Module.consts.SOME_CONST_ARRAY);\n\t\t\n\t\t// value of {x: StdTypes.Int, y: StdTypes.Int}\n\t\ttrace(Shader.c.SOME_CONST_STRUCT);\n\t\t\n\t\t// DO NOT do this; you will obtain nothing\n\t\t// trace(Module.SOME_CONST_INT);\n\t}\n}\n```\n\n### Operator Precedence\n\nDue to Haxe's bizarre operator precedence, compile-time constants **may take unexpected values**.\n\nIn Haxe, priority of bitwise operators `\u0026`, `|`, and `^` is **all the same**, which means the following two statements are the same in Haxe.\n\n```hx\n1 \u0026 2 | 3 ^ 4 \u0026 5;\n(((1 \u0026 2) | 3) ^ 4) \u0026 5;\n```\n\nIn most languages, however, `\u0026` \u003e `^` \u003e `|` holds in terms of priority. So the following two statements are the same in those languages.\n\n```cpp\n1 \u0026 2 | 3 ^ 4 \u0026 5;\n(1 \u0026 2) | (3 ^ (4 \u0026 5));\n```\n\nThis is also true for GLSL. Since compiled source code of an HGSL shader will be compiled again by a GLSL compiler, precedence of operators will be the same as that of GLSL, so no worries.\n\nWhen it comes to compile-time constants, however, they will be affected by Haxe's operator precedence because of **constant folding** done by HGSL.\n\n```hx\nfinal A = 1, B = 2, C = 3, D = 4, E = 5;\nfinal a = A \u0026 B | C ^ D \u0026 E; // this will be folded\nvar   b = A \u0026 B | C ^ D \u0026 E; // this will not be folded\na == b; // false at runtime, because of the different operator precedence\n        //   between Haxe and GLSL\n```\n\nTo avoid this strange behavior, **always use parentheses when you use bitwise operators**.\n\n```hx\nfinal A = 1, B = 2, C = 3, D = 4, E = 5;\nfinal a = (A \u0026 B) | (C ^ (D \u0026 E)); // this will be folded\nvar   b = (A \u0026 B) | (C ^ (D \u0026 E)); // this will not be folded\na == b; // true, yes they are the same!\n```\n\nThis is also true for modulo operator `%`; in Haxe, `%` has higher priority than `*` has.\nYou can access [the complete operators precedence list here](https://haxe.org/manual/expression-operators-precedence.html).\n\nTo be honest, this can be technically avoided by reconstructing ASTs, but it's not done anyways. I may implement that in future, or not.\n\n## Limitations\n\n- Any kinds of recursive function calls are not allowed, even if it is obvious to stop within a certain depth\n\t- This will result in a runtime error\n\t- (This can actually be checked at compile time without much effort, but it's not done yet)\n- Mutual reference between shaders/modules/structures may result in (non-informative) compile errors\n\t- \"Reference\" includes inheritance, function call, variable access, and type reference\n\t- Make sure there is no circular reference in your shaders; keep the dependencies a DAG!\n\n## Examples\n\nCan be found in [`examples`](./examples/) directory.\n\n## Known issues\n\nHGSL heavily uses Haxe's build macro, and it sometimes causes some strange behavior, including\n\n- Stack overflow on compilation\n- Completions getting heavier and heavier\n- Shows wrong information on hover / completions does not work on certain places ([corresponding issue](https://github.com/HaxeFoundation/haxe/issues/10673))\n\nExcept for the last one, you can fix these issues by restarting Haxe's language server. Open Command Palette and choose `Haxe: Restart Language Server`.\n\nFor the last one, **try putting much whitespace** before the completion point. You can delete it after writing the code at the point. I know this is kind of a very bad workaround, but it works anyway and getting no completions is worse than that. I hope it gets fixed soon.\n1. You got no completion candidates.  \n![](https://i.imgur.com/ysDzSGO.png)\n2. Put much whitespace. Double it if you still get no candidates.  \n![](https://i.imgur.com/JaG9dKb.png)\n3. There it is!  \n![](https://imgur.com/2AooIPp.png)\n\n## Questions\n\nSend me replies on [twitter](https://twitter.com/shr_id)!\n","funding_links":[],"categories":["Haxe","Uncategorized","Miscellaneous"],"sub_categories":["Uncategorized","Shaders"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaharan%2FHGSL","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsaharan%2FHGSL","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsaharan%2FHGSL/lists"}