Workarounds

While it’s not required to have the C# code without any syntax errors in order to edit it in Visual Studio, or convert it to valid GLSL code, it’s still very convenient to use code analysis where C# syntax errors could indicate possible GLSL errors as well.
To keep the errors list in Visual Studio clean, and still have the C# code convertible to a valid GLSL code, the following workarounds could be applied:

Floating Points

C# literals are of type double by default (without an f suffix), while GLSL literals are of type float. This is causing casting errors (CS0664) while writing a “GLSL like” code in C#, were double literals are assigned to float value types.

The Environment provides a Float type, with _float, and float_ aliases, that has an implicit casting between float and double, and can be used to eliminated these errors in most cases.

Note

When a casting error is encountered, replacing a float type with a _float or float_, could eliminate it, in other cases an f suffix could be added to the literal instead.

Intended GLSL code
float x = 1.23;
C# workarounds
// using a double literal
_float x = 1.23; // Float type alias
float_ x = 1.23; // Float type alias

// using a float literal (the suffix would be removed)
float x = 1.23f; // float primitive type

For methods declaration (input parameters, and return type), it’s recommended to always use the Float type instead of the float primitive, so that double literals could be passed as parameters values, or returned without casting.

Example:

// use a "Float" type (float_), instead of a float primitive, for both
// input parameter type, and return type.
float_ sqrtSafe(float_ value)
{
    if (value < 0.0)
    {
        // a double literal can be used as a return value (no need for
        // a suffix, "0.0f")
        return 0.0;
    }

    return sqrt(value);
}

...

// a double literal can be used as an input parameter value (no need for
// a suffix, "2.0f")
float result = sqrtSafe(2.0);

Casts

C# cast syntax is different from GLSL, for example a cast from float to int is (int)1.0 in C# and int(1.0) in GLSL. The _int() or int_() Environment methods could be used instead.

Similar methods are also defined for bool, uint, and float.

Intended GLSL code
int x = int(position.x);
C# workarounds
int x = _int(position.x);
int x = int_(position.x);

Uniforms

To declare a uniform, a field could be used, with a uniform conversion rule, a const or readonly modifier could be added to reduce warnings, and would be removed by the rule.
The conversion rule can have additional line annotation properties that would be preserved, and parsed as part of the GLSL code.

Intended GLSL code
//@uniform, min: 0.0, step: 0.1
uniform vec2 value = vec2(1.0, 2.0);
C# workaround
//@uniform, min: 0.0, step: 0.1
readonly vec2 value = vec2(1.0, 2.0);

Consts

Environment types such as vec2, mat3 are not primitive types, and cannot be declared with the const modifier, instead a readonly modifier, or a const conversion rule (for local variables) could be used.

Intended GLSL code
const vec2 value = vec2(1.0, 2.0);
C# workarounds
class Image
{
    readonly vec2 value = vec2(1.0, 2.0);

    float getValue()
    {
        //@const
        vec2 value = vec2(1.0, 2.0);
    }
}

Defines

C# does not support define directives with a value, or macros, a define conversion rule could to be used instead.

Intended GLSL code:
#define PI 3.14159265
C# workaround
//@define
float PI = 3.14159265f;
Intended GLSL code
#define sqr(x) ((x) * (x))
C# workaround
//@define
float sqr(float x) => ((x) * (x));

Overloads could be added with a remove-line conversion rule.

//@remove-line
vec2 sqr(vec2 x) => x * x;

//@remove-line
vec3 sqr(vec3 x) => x * x;

Automatic Conversion

Arrays

C# array initialization uses curly brackets, while GLSL uses round ones.
Arrays can be automatically converted when a type is specified (use new int[], and not new[]).

  • new int[]{ 1, 2, 3 } (C#) is converted to int[]( 1, 2, 3 ) (GLSL).

A multi-line array conversion is also supported.

Preprocessor Directives

C# uses the #if directive for both conditions and symbols testing, while GLSL uses #if for conditions, and #ifdef / #ifndef for symbols.

Symbol testing directives are automatically converted.

  • #if A (C#) is converted to #ifdef A (GLSL)

  • #if !A (C#) is converted to #ifndef A (GLSL)

More advanced directives could be converted with custom line rules.

Modifiers

C# modifiers are automatically removed or replaced.

  • ref and out parameter modifiers are removed from functions calls, and ref is converted to inout in functions declarations.

    • Declaration conversion:
      void modifyValue(ref int value) { ... } (C#)
      void modifyValue(inout int value) { ... } (GLSL)

    • Call conversion:
      modifyValue(ref value); (C#)
      modifyValue(value); (GLSL)

      getValue(out value); (C#)
      getValue(value); (GLSL)

  • public private internal protected virtual override static modifiers are removed.

  • readonly modifier is converted to const.

Other Workarounds

Other incompatibilities between C# and GLSL should be resolvable by using replace-line, or other custom conversion rules.