Godot Version
4.0+
Question
I’m attempting to convert parts of https://www.shadertoy.com/view/43t3WX for use in Godot, working through my limited grasp of shader code. What I have so far:
shader_type canvas_item;
// — Uniforms —
uniform sampler2D FONT_TEXTURE : filter_linear;
uniform float FONT_SPACING = 2.0;
// — Character Definitions —
#define __ 32 // " "
#define _EX 33 // " ! "
#define _DBQ 34 // " " "
#define _NUM 35 // " # "
#define _DOL 36 // " $ "
#define _PER 37 // " % "
#define _AMP 38 // " & "
#define _QT 39 // " ’ "
#define _LPR 40 // " ( "
#define _RPR 41 // " ) "
#define _MUL 42 // " * "
#define _ADD 43 // " + "
#define _COM 44 // " , "
#define _SUB 45 // " - "
#define _DOT 46 // " . "
#define _DIV 47 // " / "
#define _COL 58 // " : "
#define _SEM 59 // " ; "
#define _LES 60 // " < "
#define _EQ 61 // " = "
#define _GE 62 // " > "
#define _QUE 63 // " ? "
#define _AT 64 // " @ "
#define _LBR 91 // " [ "
#define _ANTI 92 // " \ "
#define _RBR 93 // " ] "
#define _UN 95 // " _ "
#define _0 48
#define _1 49
#define _2 50
#define _3 51
#define _4 52
#define _5 53
#define _6 54
#define _7 55
#define _8 56
#define _9 57
#define _A 65
#define _B 66
#define _C 67
#define _D 68
#define _E 69
#define _F 70
#define _G 71
#define _H 72
#define _I 73
#define _J 74
#define _K 75
#define _L 76
#define _M 77
#define _N 78
#define _O 79
#define _P 80
#define _Q 81
#define _R 82
#define _S 83
#define _T 84
#define _U 85
#define _V 86
#define _W 87
#define _X 88
#define _Y 89
#define _Z 90
#define _a 97
#define _b 98
#define _c 99
#define _d 100
#define _e 101
#define _f 102
#define _g 103
#define _h 104
#define _i 105
#define _j 106
#define _k 107
#define _l 108
#define _m 109
#define _n 110
#define _o 111
#define _p 112
#define _q 113
#define _r 114
#define _s 115
#define _t 116
#define _u 117
#define _v 118
#define _w 119
#define _x 120
#define _y 121
#define _z 122
// — Core Logic Helpers —
#define print_char(i) texture(FONT_TEXTURE, u + vec2(float(i) - float(x) / FONT_SPACING + FONT_SPACING / 8., 15. - float(i) / 16.) / 16.).r
#define makeStr(func_name) \
float func_name(vec2 u) { \
if (u.x < 0. || abs(u.y - .03) > .03) return 0.; \
int str[] = int[](
#define _end 0); \
int x = int(u.x * 16. * FONT_SPACING); \
if (x >= str.length() - 1) return 0.; \
return print_char(str[x]); \
}
// — String Definitions —
makeStr(printGodot) _G _o _d _o _t __ _V _e _r _s _i _o _n _end
void fragment() {
// Godot uses SCREEN_PIXEL_SIZE to simulate iResolution
vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
vec2 uv = FRAGCOORD.xy / iResolution.y;
vec3 col = vec3(0.0);
// Initial positioning
uv.y -= 0.9;
uv = uv * 0.8 - vec2(0.02, 0.0);
// Color definitions translated from Shadertoy
vec3 orange = (1.0 + cos(uv.y * 12.0 + 0.7 + vec3(0.0, 1.0, 2.0)));
// 1. Static Text
col += orange * printGodot(uv * 0.8);
COLOR = vec4(col, 1.0);
}
The problem comes at the line
makeStr(printGodot) _G _o _d _o _t __ _V _e _r _s _i _o _n _end
with the error as: Expected a ‘{‘, nothing I’ve done with my limited & augmented understanding has come on a solution, and made the issue more convoluted.
I’m putting this out there for someone with a greater understanding of Godot shader code to help me make sense of and learn a little more about shaders.
edits: cleanup code and language. The primary issue is the complex makeStr and _end defines, I guess thats not allowed so a simpler method must be refactored in.
Doing a bit of rearranging and rethinking yields:
class_name WTT
extends Shader
const defs:Dictionary[String,int] = {
" ": 32, #define __ 32 // " "
"!": 33, #define _EX 33 // " ! "
"E": 69, #define _E 69
"S": 83, #define _S 83
"T": 84, #define _T 84
}
const coded:StringName = r'''
shader_type canvas_item;
uniform sampler2D FONT_TEXTURE : filter_linear;
uniform float FONT_SPACING = 2.0;
uniform int MESSAGE[16];
uniform int MESSAGE_ACTUAL;
#define print_char(i) \
texture(FONT_TEXTURE, u + vec2(float(i) - float(x) / FONT_SPACING + FONT_SPACING / 8., 15. - float(i) / 16.) / 16.).r
float render_message(vec2 u) {
if (u.x < 0. || abs(u.y - .03) > .03) return 0.;
int x = int(u.x * 16. * FONT_SPACING);
if (x >= MESSAGE_ACTUAL - 1) return 0.;
return print_char(MESSAGE[x]);
}
void fragment() {
// Godot uses SCREEN_PIXEL_SIZE to simulate iResolution
vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
vec2 uv = FRAGCOORD.xy / iResolution.y;
vec3 col = vec3(0.0);
// Initial positioning
uv.y -= 0.9;
uv = uv * 0.8 - vec2(0.02, 0.0);
// Color definitions translated from Shadertoy
vec3 orange = (1.0 + cos(uv.y * 12.0 + 0.7 + vec3(0.0, 1.0, 2.0)));
// Static Text
col += orange * render_message(uv * 0.8);
COLOR = vec4(col, 1.0);
}
'''
const FONT_TEXTURE:StringName = &"FONT_TEXTURE"
const font_path:StringName = &"res://local/resources/codepage12.png"
const MESSAGE:StringName = &"MESSAGE"
const MESSAGE_ACTUAL:StringName = &"MESSAGE_ACTUAL"
var _arrayed:Array[int]
func _init(m:ShaderMaterial=null, w:String="T E S T !") -> void:
set_code(coded)
_arrayed = _to_arrayed(w)
on_material(m)
prints(_arrayed, _arrayed.size(), font_path)
static func _to_arrayed(w:String) -> Array[int]:
var a:Array[int]
a.resize(256)
var spl:PackedStringArray = w.split("")
for i in range(spl.size()):
a[i] = defs.get(spl[i], 0)
return a
func on_material(m:ShaderMaterial) -> void:
if m:
m.set_shader_parameter(MESSAGE, _arrayed)
m.set_shader_parameter(MESSAGE_ACTUAL, _arrayed.size())
m.set_shader_parameter(FONT_TEXTURE, load(font_path))
But this only results in:
Its progress, but not the end result and is just jank to boot. Any suggestions appreciated.
@normalized likes shaders.
Where’s the texture?
This hackery is not a good learning material 
The error from your initial post is caused by difference in array definition syntax between GLSL and Godot’s shading language.
In GLSL it’s:
const int[] foo = int[](1, 2, 3);
While in Godot it’s:
const int[] foo = {1, 2, 3};
That’s why Godot is complaining that it expects {
So when you change that inside makeStr macro, The error should go away:
float func_name(vec2 u) { \
if (u.x < 0. || abs(u.y - .03) > .03) return 0.; \
int str[] = {
#define _end 0}; \
int x = int(u.x * 16. * FONT_SPACING); \
if (x >= str.length() - 1) return 0.; \
return print_char(str[x]); \
}
1 Like
Ok, thats one thing I did not see. I did try fiddle with that momentarily, but didn’t get it. Its obvious now when its shown to me.
Just a copy the texture at shadertoy
1 Like
However, running that doesn’t quite get there
SHADER ERROR: Global non-constant variables are not supported. Expected ‘const’ keyword before constant definition.
at: (null) (:106)
105 |
E 106-> int str
= {
107 |
108 |
109 |
110 |
111 |
112 |
113 | float printGodot(vec2 u) { if (u.x < 0. || abs(u.y - .03) > .03) return 0.; \ 71 111 100 111 116 32 86 101 114 115 105 111 110 0}; int x = int(u.x * 16. * FONT_SPACING); if (x >= str.length() - 1) return 0.; return texture(FONT_TEXTURE, u + vec2(float(str
) - float(x) / FONT_SPACING + FONT_SPACING / 8., 15. - float(str
) / 16.) / 16.).r ; }
My advice is to unroll the main macros so you can see the actual code in one piece. That way it’ll be much easier to spot syntax incompatibilities.
1 Like