Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions data/shader_test.gdshader
Original file line number Diff line number Diff line change
@@ -1,9 +1,120 @@
shader_type canvas_item;
render_mode unshaded, light_only;

#include "some_include.gdshaderinc"

// Types.

struct PointLight {
vec3 position;
vec3 color;
float intensity;
};

// Constants.

const float GOLDEN_RATIO = 1.618033988749894;

// Uniforms.

uniform float blur_amount: hint_range(0.0, 10.0) = 0.0;
uniform sampler2D SCREEN_TEXTURE: hint_screen_texture, filter_linear_mipmap;

group_uniforms stripes;
uniform int stripes_orientation: hint_range(0, 1) = 0;
uniform highp vec4 stripes_direction = vec4(0.0, 1.0, 2.0, 3.0);
group_uniforms stripes.speed;
uniform mediump float stripes_speed = 1.0;
group_uniforms;

global uniform mat3 transform;
instance uniform vec4 my_color: source_color = vec4(1.0, 0.5, 0.0, 1.0);

// Varyings.

varying float saturation;
varying flat int frame_index;
varying lowp vec4 light_data;
varying PointLight point_light;

// Built-in methods.

void fragment() {
float float_arr[3] = float[3] (1.0, 0.5, 0.0);
int int_arr[3] = int[] (2, 1, 0);
vec2 vec2_arr[3] = { vec2(1.0, 1.0), vec2(0.5, 0.5), vec2(0.0, 0.0) };
bool bool_arr[] = { true, true, false };

vec4 blurred = texture(SCREEN_TEXTURE, SCREEN_UV, blur_amount);
COLOR = vec4(blurred.rgb, 1.0);

if (saturation > 0.5) {
COLOR.a = 0.45;
}
}

void light() {
PointLight light;
light.position = vec3(0.0);
light.color = vec3(1.0, 0.0, 0.0);
light.intensity = 0.5;

#if defined(SHADOW_QUALITY_HIGH)
// High shadow quality.
#elif defined(SHADOW_QUALITY_MEDIUM)
// Medium shadow quality.
#else
// Low shadow quality.
#endif
}

// Custom methods.

// Based on https://github.com/ttencate/blur_godot4/blob/0517d1159b088a272300b083ae98376d9d77ffea/Blur.gdshader.
float blur(sampler2D source, vec2 uv, vec2 direction, float intensity) {
vec2 s = intensity * direction / vec2(textureSize(source, 0));

float blurred =
0.011194727 * texture(source, uv - 10.000000000 * s).a +
0.039368696 * texture(source, uv - 8.415809477 * s).a +
0.071308558 * texture(source, uv - 6.435363708 * s).a +
0.110237219 * texture(source, uv - 4.455121108 * s).a +
0.145451038 * texture(source, uv - 2.475020813 * s).a +
0.163798995 * texture(source, uv - 0.495000167 * s).a +
0.157439298 * texture(source, uv + 1.485004498 * s).a +
0.129158204 * texture(source, uv + 3.465057055 * s).a +
0.090434685 * texture(source, uv + 5.445220765 * s).a +
0.054043977 * texture(source, uv + 7.425557483 * s).a +
0.027564604 * texture(source, uv + 9.406126897 * s).a;

// Allows to disable the effect completely at the cost of being applied twice.
blurred *= intensity;

return blurred;
}

// Custom defines.

#define CONSUME_INSTANCE_DATA \
if (use_overrides) { \
variant_index = variant_index_override; \
frame_index = frame_index_override; \
opacity = opacity_override; \
saturation = saturation_override; \
} else { \
variant_index = int(INSTANCE_CUSTOM.r); \
frame_index = int(INSTANCE_CUSTOM.g); \
opacity = INSTANCE_CUSTOM.b; \
saturation = 1.0; \
}

#define TEXTURE_FRAME_FUNC(name) \
vec4 name(sampler2D source, vec2 uv, int fidx) { \
vec2 sample_uv = uv; \
sample_uv.x = (sample_uv.x + float(fidx % frame_count.x)) / float(frame_count.x); \
sample_uv.y = (sample_uv.y + float(fidx / frame_count.x)) / float(frame_count.y); \
\
return texture(source, sample_uv); \
}
TEXTURE_FRAME_FUNC(texture_frame)
TEXTURE_FRAME_FUNC(texture_frame2)
2 changes: 1 addition & 1 deletion languages/gdscript/highlights.scm
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@
; Function
"func" @keyword.function

; Action
; Control flow
[
"if"
"else"
Expand Down
136 changes: 100 additions & 36 deletions languages/gdshader/highlights.scm
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,34 @@

; Keywords
[
"render_mode"
"shader_type"
"render_mode"
"group_uniforms"
"uniform"
"varying"
"global"
"instance"
"const"
"varying"
"uniform"
; type
"struct"
; modifiers
] @keyword

[
(shader_type)
(render_mode)
(hint_name)
] @attribute

; Modifiers
[
"in"
"out"
"inout"
(precision_qualifier)
(interpolation_qualifier)
] @keyword.modifier

; Control flow
[
; repeat
"while"
"for"
Expand All @@ -32,11 +44,9 @@
"switch"
"case"
"default"
; directive
"#"
"include"
] @keyword
] @keyword.control

; Operators
[
"="
"+="
Expand Down Expand Up @@ -65,13 +75,54 @@
"--"
] @operator

; Types
(boolean) @boolean
[
(integer)
(float)
] @number
(string) @string
; Preprocessor
; Preprocessor words cannot be targetted completely because the parser
; errs around many of them, or just doesn't recognize them as valid nodes.
; Related to that, we can also not match "defined" well, since it detects
; as a function call (in an invalid context).
; Also not that the "#" symbol is NOT a part of the node, it's a separate
; node even when matched correctly. E.g. `#include` parsed into "#" and
; "include".
(
"#" @keyword.preproc @preproc
. ; Direct siblings only.
[
;"define"
;"undef"
;"ifdef"
;"ifndef"
"if"
"elif"
"else"
;"endif"
;"error"
"include"
;"pragma"
] @keyword.preproc @preproc)
; Explicitly match inside errors, because they don't match above.
(ERROR
(
"#" @keyword.preproc @preproc
. ; Direct siblings only.
[
;"define"
;"undef"
;"ifdef"
;"ifndef"
"if"
"elif"
"else"
;"endif"
;"error"
"include"
;"pragma"
] @keyword.preproc @preproc))

;"defined" @keyword.preproc @preproc

; As a temporary solution we highlight "#" individually, so there is at
; least something.
"#" @keyword.preproc @preproc

; Delimiters
[
Expand All @@ -89,47 +140,60 @@
"}"
] @punctuation.bracket

[
(builtin_type)
(ident_type)
] @type
; Comments
(comment) @comment

; Built-in types
(boolean) @boolean
[
(shader_type)
(render_mode)
(hint_name)
] @attribute
(integer)
(float)
] @number
(string) @string

(builtin_variable) @constant
(builtin_type) @type.builtin
(builtin_variable) @constant.builtin
(builtin_function) @function.builtin

(builtin_function) @function
; User declarations

(ident) @variable
(ident_type) @type

(group_uniforms_declaration
group_name: (ident) @attribute)
(group_uniforms_declaration
group_name: (ident) @property
subgroup_name: (ident) @property)
group_name: (ident) @attribute
subgroup_name: (ident) @attribute)

(struct_declaration
name: (ident) @type)

(struct_member
name: (ident) @property)

(const_declaration
specifier: (var_specifier
name: (ident) @constant))
(uniform_declaration
specifier: (var_specifier
name: (ident) @property))
(varying_declaration
specifier: (var_specifier
name: (ident) @property))

(function_declaration
name: (ident) @function)

(parameter
name: (ident) @variable.special)
name: (ident) @variable.parameter)

(member_expr
member: (ident) @property)

(call_expr
function: [
(ident)
(builtin_type)
] @function)
function: (ident) @function)

; Not actually a function call, but rather a type constructor/literal.
(call_expr
function: (builtin_type) @function)

(comment) @comment
function: (builtin_type) @type.builtin)