glsl vscode写_使用Visual Studio SDK制作GLSL词法着色插件

本文介绍了如何利用Visual Studio SDK创建一个GLSL语法高亮插件。通过创建Editor Classifier模版项目,定义GLSL的着色类型,并导出着色类型,最后关联GLSL文件扩展名,实现对GLSL代码的语法着色。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原作者故意写错了一点东西,这就让那些一点脑筋也不想动的小伙伴得不到想要的结果。我在这里把那些地方纠正过来了。

使用Visual Studio SDK制作GLSL词法着色插件

我们在Visual Studio上开发OpenGL ES项目时,避免不了写Shader。这时在vs里直接编辑shader就会显得很方便。但是vs默认是不支持GLSL的语法着色的,我们只好自己动手创造。最简单的实现自定义语法着色的方法就是创建一个VSIX插件包,我们只需要安装Visual Studio SDK,使用内置的模版就可以构建一个插件项目。

1. 安装Visual Studio SDK

双击安装,一路next即可。

安装完毕后我们可以在新建项目->模版->C#中看到“扩展性”这一条目,这些就是开发插件用的模版了。

2. 创建插件项目

新建项目,在扩展性标签中,选择Editor Classifier模版,命名为ShaderEditor,点击确定。

Visual Studio为我们生成了如下几个文件。

ShaderEditorFormat.cs文件的默认代码如下:

1 [Export(typeof(EditorFormatDefinition))]

2 [ClassificationType(ClassificationTypeNames = "ShaderEditor")]

3 [Name("ShaderEditor")]

4 [UserVisible(true)] //this should be visible to the end user

5 [Order(Before = Priority.Default)] //set the priority to be after the default classifiers

6 internal sealed class ShaderEditorFormat : ClassificationFormatDefinition {

7 ///

8 /// Defines the visual format for the "ShaderEditor" classification type

9 ///

10 public ShaderEditorFormat() {

11 this.DisplayName = "ShaderEditor"; //human readable version of the name

12 this.BackgroundColor = Colors.BlueViolet;

13 this.TextDecorations = System.Windows.TextDecorations.Underline;

14 }

15 }

这段代码定义了一个名为"ShaderEditor"的着色类型,编译工程并运行,我们可以在Visual Studio实验实例的工具->选项->字体和颜色中找到一个名为"ShaderEditor"的条目。同时我们会发现所有文本文件的颜色都变成了Colors.BlueViolet并带上了下划线。修改this.DisplayName = "ShaderEditor"的内容,可以改变在字体和颜色中显示的名字。下面的格式设置可以任意修改成喜欢的样式,但要注意在这里的格式只是插件首次安装时的默认设置,这些条目和其它着色选项一样,都可以被用户任意更改。

3. 创建GLSL的着色类型

我们已经了解了如何将着色类型添加到Visual Studio,现在修改ShaderEditorFormat.cs,添加我们的着色类型。

1 #region Format definition

2 [Export(typeof(EditorFormatDefinition))]3 [ClassificationType(ClassificationTypeNames = "GLSLText")]4 [Name("GLSLText")]5 [UserVisible(true)]6 [Order(Before =Priority.Default)]7 internal sealed classGLSLTextFormatDefinition : ClassificationFormatDefinition8 {9 publicGLSLTextFormatDefinition()10 {11 this.DisplayName = "GLSL文本";12 this.ForegroundColor =Colors.Brown;13 }14 }15

16 [Export(typeof(EditorFormatDefinition))]17 [ClassificationType(ClassificationTypeNames = "GLSLIdentifier")]18 [Name("GLSLIdentifier")]19 [UserVisible(true)]20 [Order(Before =Priority.Default)]21 internal sealed classGLSLIdentifierFormatDefinition : ClassificationFormatDefinition22 {23 publicGLSLIdentifierFormatDefinition()24 {25 this.DisplayName = "GLSL标识符";26 this.ForegroundColor =Colors.Brown;27 }28 }29

30 [Export(typeof(EditorFormatDefinition))]31 [ClassificationType(ClassificationTypeNames = "GLSLComment")]32 [Name("GLSLComment")]33 [UserVisible(true)]34 [Order(Before =Priority.Default)]35 internal sealed classGLSLCommentFormatDefinition : ClassificationFormatDefinition36 {37 publicGLSLCommentFormatDefinition()38 {39 this.DisplayName = "GLSL注释";40 this.ForegroundColor =Colors.DarkGray;41 }42 }43

44 [Export(typeof(EditorFormatDefinition))]45 [ClassificationType(ClassificationTypeNames = "GLSLKeyword")]46 [Name("GLSLKeyword")]47 [UserVisible(true)]48 [Order(Before =Priority.Default)]49 internal sealed classGLSLKeywordFormatDefinition : ClassificationFormatDefinition50 {51 publicGLSLKeywordFormatDefinition()52 {53 this.DisplayName = "GLSL关键字";54 this.ForegroundColor =Colors.Blue;55 }56 }57

58 [Export(typeof(EditorFormatDefinition))]59 [ClassificationType(ClassificationTypeNames = "GLSLClass")]60 [Name("GLSLClass")]61 [UserVisible(true)]62 [Order(Before =Priority.Default)]63 internal sealed classGLSLClassFormatDefinition : ClassificationFormatDefinition64 {65 publicGLSLClassFormatDefinition()66 {67 this.DisplayName = "GLSL类型";68 this.ForegroundColor =Colors.Green;69 }70 }71

72 [Export(typeof(EditorFormatDefinition))]73 [ClassificationType(ClassificationTypeNames = "GLSLQualifier")]74 [Name("GLSLQualifier")]75 [UserVisible(true)]76 [Order(Before =Priority.Default)]77 internal sealed classGLSLQualifierFormatDefinition : ClassificationFormatDefinition78 {79 publicGLSLQualifierFormatDefinition()80 {81 this.DisplayName = "GLSL限定符";82 this.ForegroundColor =Colors.Pink;83 }84 }85

86 [Export(typeof(EditorFormatDefinition))]87 [ClassificationType(ClassificationTypeNames = "GLSLVariable")]88 [Name("GLSLVariable")]89 [UserVisible(true)]90 [Order(Before =Priority.Default)]91 internal sealed classGLSLVariableFormatDefinition : ClassificationFormatDefinition92 {93 publicGLSLVariableFormatDefinition()94 {95 this.DisplayName = "GLSL系统变量";96 this.ForegroundColor =Colors.DarkOrange;97 }98 }99

100 [Export(typeof(EditorFormatDefinition))]101 [ClassificationType(ClassificationTypeNames = "GLSLFunction")]102 [Name("GLSLFunction")]103 [UserVisible(true)]104 [Order(Before =Priority.Default)]105 internal sealed classGLSLFunctionFormatDefinition : ClassificationFormatDefinition106 {107 publicGLSLFunctionFormatDefinition()108 {109 this.DisplayName = "GLSL系统函数";110 this.ForegroundColor =Colors.DarkTurquoise;111 }112 }113 #endregion //Format definition

4. 导出着色类型

Editor Classifier使用了MEF框架,关于MEF的具体细节,请参考MSDN的相关文档。

我们需要注意的是,在MEF中,光定义了着色类型还不够,我们需要导出一个ClassificationTypeDefinition,才能在系统中生效。

打开ShaderEditorType.cs,我们看到系统生成的代码如下:

1 internal static class ShaderEditorClassificationDefinition {

2 [Export(typeof(ClassificationTypeDefinition))]

3 [Name("ShaderEditor")]

4 internal static ClassificationTypeDefinition ShaderEditorType = null;

5 }

这里的Name与之前默认生成的ShaderEditor相同,同理,我们将这里的代码修改成方才定义的类型

1 internal static classShaderEditorClassificationDefinition2 {3 [Export(typeof(ClassificationTypeDefinition))]4 [Name("GLSLText")]5 internal static ClassificationTypeDefinition GLSLTextType = null;6

7 [Export(typeof(ClassificationTypeDefinition))]8 [Name("GLSLIdentifier")]9 internal static ClassificationTypeDefinition GLSLIdentifierType = null;10

11 [Export(typeof(ClassificationTypeDefinition))]12 [Name("GLSLComment")]13 internal static ClassificationTypeDefinition GLSLCommentType = null;14

15 [Export(typeof(ClassificationTypeDefinition))]16 [Name("GLSLKeyword")]17 internal static ClassificationTypeDefinition GLSLKeywordType = null;18

19 [Export(typeof(ClassificationTypeDefinition))]20 [Name("GLSLClass")]21 internal static ClassificationTypeDefinition GLSLClassType = null;22

23 [Export(typeof(ClassificationTypeDefinition))]24 [Name("GLSLQualifier")]25 internal static ClassificationTypeDefinition GLSLQualifierType = null;26

27 [Export(typeof(ClassificationTypeDefinition))]28 [Name("GLSLVariable")]29 internal static ClassificationTypeDefinition GLSLVariableType = null;30

31 [Export(typeof(ClassificationTypeDefinition))]32 [Name("GLSLFunction")]33 internal static ClassificationTypeDefinition GLSLFunctionType = null;34 }

5. 关联文件类型

打开ShaderEditor.cs

1 [Export(typeof(IClassifierProvider))]

2 [ContentType("text")]

3 internal class ShaderEditorProvider : IClassifierProvider {

4 [Import]

5 internal IClassificationTypeRegistryService ClassificationRegistry = null; // Set via MEF

6

7 public IClassifier GetClassifier(ITextBuffer buffer) {

8 return buffer.Properties.GetOrCreateSingletonProperty(delegate { return new ShaderEditor(ClassificationRegistry); });

9 }

10 }

代码ContentType("text")创建了一个Provider并将它们对所有text类型的文件生效。

GLSL主要的文件扩展名为.vsh和.fsh,为了只对这两个扩展名生效,我们需要自定义一个ContentType,并创建两个扩展名关联。将上述代码修改为:

1 [Export(typeof(ITaggerProvider))]2 [ContentType("glsl")]3 [TagType(typeof(ClassificationTag))]4 internal sealed classGLSLClassifierProvider : ITaggerProvider {5

6 [Export]7 [Name("glsl")]8 [BaseDefinition("code")]9 internal static ContentTypeDefinition GLSLContentType = null;10

11 [Export]12 [FileExtension(".vsh")]13 [ContentType("glsl")]14 internal static FileExtensionToContentTypeDefinition GLSLVshType = null;15

16 [Export]17 [FileExtension(".fsh")]18 [ContentType("glsl")]19 internal static FileExtensionToContentTypeDefinition GLSLFshType = null;20

21 [Import]22 internal IClassificationTypeRegistryService classificationTypeRegistry = null;23

24 [Import]25 internal IBufferTagAggregatorFactoryService aggregatorFactory = null;26

27 public ITagger CreateTagger(ITextBuffer buffer) whereT : ITag {28 return new GLSLClassifier(buffer, classificationTypeRegistry) as ITagger;29 }30 }

(这段代码有问题,请用我改过的)

1 [Export(typeof(ITaggerProvider))]2 [ContentType("glsl")]3 [TagType(typeof(ClassificationTag))]4 internal sealed classGLSLClassifierProvider : ITaggerProvider5 {6

7 [Export]8 [Name("glsl")]9 [BaseDefinition("code")]10 internal static ContentTypeDefinition GLSLContentType = null;11

12 [Export]13 [FileExtension(".vert")]14 [ContentType("glsl")]15 internal static FileExtensionToContentTypeDefinition GLSLVshType = null;16

17 [Export]18 [FileExtension(".frag")]19 [ContentType("glsl")]20 internal static FileExtensionToContentTypeDefinition GLSLFshType = null;21

22 [Export]23 [FileExtension(".geom")]24 [ContentType("glsl")]25 internal static FileExtensionToContentTypeDefinition GLSLGshType = null;26

27 [Import]28 internal IClassificationTypeRegistryService classificationTypeRegistry = null;29

30 [Import]31 internal IBufferTagAggregatorFactoryService aggregatorFactory = null;32

33 public ITagger CreateTagger(ITextBuffer buffer) whereT : ITag34 {35 return new GLSLClassifier(buffer, classificationTypeRegistry) as ITagger;36 }37 }

这样我们就创建了只针对vert、frag和geom文件生效的Editor。也就是顶点Shader、片段Shader和几何Shader。

6. 使用gplex进行词法分析

我们需要使用词法分析扫描器来实现具体的着色功能,gplex可以为我们生成C#语言的扫描器,下载地址:

解压后在binaries文件夹下找到gplex.exe,把它拷贝到项目的根目录下。

在项目根目录下新建一个GLSL文件夹,新建GLSLLexer.lex文件。并把它们添加到proj中。

在proj上右键->属性,在生成事件选项卡中,在预先生成事件命令行中输入

cd $(ProjectDir)GLSL\

$(ProjectDir)\gplex GLSLLexer

打开GLSLLexer.lex,写入以下代码:

1 %option unicode, codepage:raw

2

3 %{

4 // User code is all now in ScanHelper.cs

5 %}

6

7 %namespace Shane

8 %option verbose, summary, noparser, nofiles, unicode

9

10 %{

11 public int nextToken() { return yylex(); }

12 public int getPos() { return yypos; }

13 public int getLength() { return yyleng; }

14 %}

15

16 //=============================================================

17 //=============================================================

18

19 number ([0-9])+

20 chars [A-Za-z]

21 cstring [A-Za-z_]

22 blank " "

23 delim [ \t\n]

24 word {chars}+

25 singleLineComment "//"[^\n]*

26 multiLineComment "/*"[^*]*\*(\*|([^*/]([^*])*\*))*\/

27

28 comment {multiLineComment}|{singleLineComment}

29 class bool|int|float|bvec|ivec|vec|vec2|vec3|vec4|mat2|mat3|mat4|sampler1D|sampler2D|sampler3D|samplerCube|sampler1DShadow|sampler2DShadow

30 keyword return|if|else|while|do|for|foreach|break|continue|switch|case|default|goto|class|struct|enum|extern|interface|namespace|public|static|this|volatile|using|in|out|true|false

31 qualifier const|attribute|uniform|varying

32 systemVariable gl_BackColor|gl_BackLightModelProduct|gl_BackLightProduct|gl_BackMaterial|gl_BackSecondaryColor|gl_ClipPlane|gl_ClipVertex|gl_Color|gl_DepthRange|gl_DepthRangeParameters|gl_EyePlaneQ|gl_EyePlaneR|gl_EyePlaneS|gl_EyePlaneT|gl_Fog|gl_FogCoord|gl_FogFragCoord|gl_FogParameters|gl_FragColor|gl_FragCoord|gl_FragData|gl_FragDepth|gl_FrontColor|gl_FrontFacing|gl_FrontLightModelProduct|gl_FrontLightProduct|gl_FrontMaterial|gl_FrontSecondaryColor|gl_LightModel|gl_LightModelParameters|gl_LightModelProducts|gl_LightProducts|gl_LightSource|gl_LightSourceParameters|gl_MaterialParameters|gl_MaxClipPlanes|gl_MaxCombinedTextureImageUnits|gl_MaxDrawBuffers|gl_MaxFragmentUniformComponents|gl_MaxLights|gl_MaxTextureCoords|gl_MaxTextureImageUnits|gl_MaxTextureUnits|gl_MaxVaryingFloats|gl_MaxVertexAttribs|gl_MaxVertexTextureImageUnits|gl_MaxVertexUniformComponents|gl_ModelViewMatrix|gl_ModelViewMatrixInverse|gl_ModelViewMatrixInverseTranspose|gl_ModelViewMatrixTranspose|gl_ModelViewProjectionMatrix|gl_ModelViewProjectionMatrixInverse|gl_ModelViewProjectionMatrixInverseTranspose|gl_ModelViewProjectionMatrixTranspose|gl_MultiTexCoord0|gl_MultiTexCoord1|gl_MultiTexCoord10|gl_MultiTexCoord11|gl_MultiTexCoord2|gl_MultiTexCoord3|gl_MultiTexCoord4|gl_MultiTexCoord5|gl_MultiTexCoord6|gl_MultiTexCoord7|gl_MultiTexCoord8|gl_MultiTexCoord9|gl_Normal|gl_NormalMatrix|gl_NormalScale|gl_ObjectPlaneQ|gl_ObjectPlaneR|gl_ObjectPlaneS|gl_ObjectPlaneT|gl_Point|gl_PointParameters|gl_PointSize|gl_Position|gl_ProjectionMatrix|gl_ProjectionMatrixInverse|gl_ProjectionMatrixInverseTranspose|gl_ProjectionMatrixTranspose|gl_SecondaryColor|gl_TexCoord|gl_TextureEnvColor|gl_TextureMatrix|gl_TextureMatrixInverse|gl_TextureMatrixInverseTranspose|gl_TextureMatrixTranspose|gl_Vertex

33 systemFunction radians|degress|sin|cos|tan|asin|acos|atan|pow|exp|log|exp2|log2|sqrt|inversesqrt|abs|sign|floor|ceil|fract|mod|min|max|clamp|mix|step|smoothstep|length|distance|dot|cross|normalize|faceforward|reflect|matrixCompMult|lessThan|lessThanEqual|greaterThan|greaterThanEqual|equal|notEqual|any|all|not|texture2D|texture2DProj|texture2DLod|texture2DProjLod|textureCube|textureCubeLod

34 identifier {cstring}+{number}*[{cstring}@]*{number}*

35

36 %%

37

38 {keyword} return (int)GLSLTokenType.Keyword;

39 {class} return (int)GLSLTokenType.Class;

40 {qualifier} return (int)GLSLTokenType.Qualifier;

41 {systemVariable} return (int)GLSLTokenType.SystemVariable;

42 {systemFunction} return (int)GLSLTokenType.SystemFunction;

43 {identifier} return (int)GLSLTokenType.Identifier;

44 {comment} return (int)GLSLTokenType.Comment;

45

46 %%

保存并关闭,这时生成一下项目,我们会看到在GLSL目录下生成了GLSLLexer.cs文件,同样把这个文件添加到proj中。

7. 处理扫描结果

接下来我们要在ShaderEditor.cs中处理我们的扫描结果,并最终对匹配的代码行进行着色。

首先删除默认创建的ShaderEditor类。

添加一个GLSLToken枚举,这个枚举就是GLSLLexer.cs返回的枚举类型,它用来通知我们当前的语句块是哪个类型。

代码如下:

1 public enumGLSLTokenType2 {3 Text = 1,4 Keyword,5 Comment,6 Identifier,7 Class,8 Qualifier,9 SystemVariable,10 SystemFunction11 }

创建我们自己的ShaderEditor类,代码如下:

1 #region Provider definition

2 [Export(typeof(ITaggerProvider))]3 [ContentType("glsl")]4 [TagType(typeof(ClassificationTag))]5 internal sealed classGLSLClassifierProvider : ITaggerProvider6 {7

8 [Export]9 [Name("glsl")]10 [BaseDefinition("code")]11 internal static ContentTypeDefinition GLSLContentType = null;12

13 [Export]14 [FileExtension(".vert")]15 [ContentType("glsl")]16 internal static FileExtensionToContentTypeDefinition GLSLVshType = null;17

18 [Export]19 [FileExtension(".frag")]20 [ContentType("glsl")]21 internal static FileExtensionToContentTypeDefinition GLSLFshType = null;22

23 [Export]24 [FileExtension(".geom")]25 [ContentType("glsl")]26 internal static FileExtensionToContentTypeDefinition GLSLGshType = null;27

28 [Import]29 internal IClassificationTypeRegistryService classificationTypeRegistry = null;30

31 [Import]32 internal IBufferTagAggregatorFactoryService aggregatorFactory = null;33

34 public ITagger CreateTagger(ITextBuffer buffer) whereT : ITag35 {36 return new GLSLClassifier(buffer, classificationTypeRegistry) as ITagger;37 }38 }39 #endregion //provider def

40

41 #region Classifier

42 internal sealed class GLSLClassifier : ITagger

43 {44 internalGLSLClassifier(ITextBuffer buffer, IClassificationTypeRegistryService typeService)45 {46 textBuffer =buffer;47 typeDic = new Dictionary();48 typeDic[GLSLTokenType.Text] = typeService.GetClassificationType("GLSLText");49 typeDic[GLSLTokenType.Identifier] = typeService.GetClassificationType("GLSLIdentifier");50 typeDic[GLSLTokenType.Keyword] = typeService.GetClassificationType("GLSLKeyword");51 typeDic[GLSLTokenType.Class] = typeService.GetClassificationType("GLSLClass");52 typeDic[GLSLTokenType.Comment] = typeService.GetClassificationType("GLSLComment");53 typeDic[GLSLTokenType.Qualifier] = typeService.GetClassificationType("GLSLQualifier");54 typeDic[GLSLTokenType.SystemVariable] = typeService.GetClassificationType("GLSLVariable");55 typeDic[GLSLTokenType.SystemFunction] = typeService.GetClassificationType("GLSLFunction");56 }57

58 public event EventHandlerTagsChanged59 {60 add { }61 remove { }62 }63

64 public IEnumerable>GetTags(NormalizedSnapshotSpanCollection spans)65 {66 IClassificationType classification =typeDic[GLSLTokenType.Text];67 string text = spans[0].Snapshot.GetText();68 yield return new TagSpan(69 new SnapshotSpan(spans[0].Snapshot, new Span(0, text.Length)),70 newClassificationTag(classification));71 scanner.SetSource(text, 0);72 inttok;73 do

74 {75 tok =scanner.nextToken();76 int pos =scanner.getPos();77 int len =scanner.getLength();78 int total =text.Length;79 if (pos < 0 || len < 0 || pos >total)80 {81 continue;82 }83 if (pos + len >total)84 {85 len = total -pos;86 }87 if (typeDic.TryGetValue((GLSLTokenType)tok, outclassification))88 {89 yield return new TagSpan(90 new SnapshotSpan(spans[0].Snapshot, newSpan(pos, len)),91 newClassificationTag(classification));92 }93 } while (tok > (int)Tokens.EOF);94 }95

96 ITextBuffer textBuffer;97 IDictionarytypeDic;98 Scanner scanner = newScanner();99 }100 #endregion //Classifier

GLSLClassifierProvider

TagsChanged事件保证在代码发生改变时实时刷新编辑器。

构造方法中,通过typeService.GetClassificationType("GLSLIdentifier")取得我们定义的实例,并把它们和枚举关联起来,

GetClassificationType的参数传入着色类型的Name。

GetTags方法是由系统调用的迭代方法,yield return new TagSpan()返回我们的着色对象,即可实现着色效果。

编译并运行,可以看到vert、fraghe geom已经有了语法着色了。

如果你实在做不出来,不如去我的Github下载源码,直接编译即可。

2016-05-14

根据GLSL4.3更新了GLSL的关键字、内置类型、内置变量、内置函数,添加了对“数值”的高亮显示。

重命名为GLGLHighlight。

为了方便换色,我把常用颜色保存到这里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值