I spent a ton of time over the past several months looking for a decent IDE around which to start seriously expanding my shader code ecosystem. Since I have quite a few custom bindings, I can't use a standalone suite out of the box, but require something that is strongly typed while also being able to leverage dynamic shared code. I want to stress that I'm NOT looking for a complete build/debug solution - just the editor/IDE portion so I can write shaders while expanding my codebase independently.
For months I thought there was nothing that would suit my needs since any extensions that deal with shading languages seem to be limited mostly to syntax hilighting. But I wanted so much more. Finally, lo and behold, I there was an answer to my call. Well, sorta. Although in all honesty it's actually a surprisingly good answer from my perspective. Thing is, it comes with a hefty caveat.
For the non-TL;DR crowd - here's what I want:
- to write clean GLSL code
- context-aware suggestions/intellisense and auto-complete for built-in intrinsics AND my own custom objects, including those imported from other modules. In realtime.
- function argument hilighting
- real-time type-checking
- code peek
- error hilighting
- fantastic syntax hilighting
- not having to fight the coding environment
- preferably not pay myself silly or, better yet, go completely free
Enter Visual Studio Code with the C/C++ extension. Thanks to the similarity of GLSL to C, it can actually do ALL of the above (except for the first point, obviously), and the whole thing is free.
Here's some more words to set up the scene:
I don't need to write C++ in vscode (that's what I have my main IDE for), so I decided to go native on it and use every underhanded trick and dirty hack I could think of to adapt the language to look and feel as if I'm writing C++ code while actually writing valid GLSL. For the most part this turned out to be far less difficult than I initially figured.
Here's what I did: after installing the C/C++ extension, I stripped out all of the default includes and started building my own single-include GLSL-as-C++ header (kinda like GLM, but without any implementations). All the while I had only one objective in mind: hack myself around GLSL semantics to avoid any erroneous inline squigglies that show up when there's an error in the code while not breaking error hilighting that's actually valid. I managed to cheat my way around swizzles, conform common operators to behave like GLSL and swindled my way around several GLSL-specific keywords and intrinsics.
But now I've encountered my first real headache.
Also, since in practice I only use a fairly small subset of GLSL, I expect there to be quite a few other bug issues, but this one is pertinent to me right now, especially since it interferes with intellisense and looks ugly.
The offending construct is uniform blocks.
Take the following piece of code in GLSL:
In GLSL, _struct is treated like a global. There are no namespaces or other scope-related concepts that would allow me to "extract" _struct from _uniblock. In fact, as far as I know, the uniform block is purely syntactic from a code-writing point of view and from a logical standpoint pretty much does not exist. This is an issue, because I want the C++ intellisense to treat _struct like a global, so I don't lose suggestions when I try to access its members.
Now, to hilight the type of connivery I'm employing - in order to deal with the layout qualifier part, I'm resolving it through the following macro:
As another example, in order to resolve something like:
I'm defining the offending keywords and qualifiers as:
Oh, and "uniform" is defined as:
Of course this isn't valid code - but it's not supposed to be. After the replacement, vscode thinks it's valid and consequently doesn't complain. Which is exactly what I want so long as I don't make a mistake while writing the shader.
Now I want to apply the same kind of logic to the uniform block problem to get rid of the implicit scope as invisibly as possible. Basically anything goes - macros, typedefs, type obfuscation via templates, and - if all else fails - modifying the GLSL syntax using the preprocessor as long as the resulting code will compile without any additional modifications.
Ideas?
Truth be told, the impact of not being able to resolve this means little more than a couple of additional red squigglies here and there and a lack of intellisense for any objects that are inside a uniform block. That being said, if there's a choice between squigglies, occasional squigglies and no squigglies, I want no squigglies.
PS - I hope my description was in the very least marginally clear