zoukankan      html  css  js  c++  java
  • CSharpGL(12)用T4模板生成CSSL及其renderer代码

    CSharpGL(12)用T4模板生成CSSL及其renderer代码

    2016-08-13

    由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了。CSharpGL源码中包含10多个独立的Demo,更适合入门参考。

    为了尽可能提升渲染效率,CSharpGL是面向Shader的,因此稍有难度。

    CSSL+Renderer

    严格来说本篇不直接涉及OpenGL,但磨刀不误砍柴工,本篇仍算CSharpGL里。

    上一篇制作了CSSL。CSSL和Renderer配合,就定义了一个渲染OpenGL元素的完整流程。本篇用T4模板来帮助开发者自动生成这个简单的代码框架。

    下载

    本篇是CSharpGL的一部分,CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入(https://github.com/bitzhuwei/CSharpGL

     

    如何使用?

    设计一个系统前,要想好用户会期望如何使用这个系统。当我想创建一个新的OpenGL元素时,只需在一处提供此元素的名字,就足以确定它的CSSL+Renderer框架。

    所以,我需要写一个T4模板,提供此名字,然后自动生成2个文件,分别存放CSSL和Renderer代码。

    T4如何生成多个文件?

    为T4重定向输出位置即可。步骤如下。

    使用ttinclude文件

    创建一个以ttinclude为扩展名的文件,输入以下内容。后面将在tt文件中引用此文件。

      1 <#@ assembly name="System.Core"#>
      2 <#@ assembly name="EnvDTE"#>
      3 <#@ import namespace="System.Collections.Generic"#>
      4 <#@ import namespace="System.IO"#>
      5 <#@ import namespace="System.Text"#>
      6 <#@ import namespace="Microsoft.VisualStudio.TextTemplating"#>
      7 
      8 <#+
      9 
     10 // T4 Template Block manager for handling multiple file outputs more easily.
     11 // Copyright (c) Microsoft Corporation.  All rights reserved.
     12 // This source code is made available under the terms of the Microsoft Public License (MS-PL)
     13 
     14 // Manager class records the various blocks so it can split them up
     15 class Manager
     16 {
     17     public struct Block {
     18         public String Name;
     19         public int Start, Length;
     20     }
     21 
     22     public List<Block> blocks = new List<Block>();
     23     public Block currentBlock;
     24     public Block footerBlock = new Block();
     25     public Block headerBlock = new Block();
     26     public ITextTemplatingEngineHost host;
     27     public ManagementStrategy strategy;
     28     public StringBuilder template;
     29     public String OutputPath { get; set; }
     30 
     31     public Manager(ITextTemplatingEngineHost host, StringBuilder template, bool commonHeader) {
     32         this.host = host;
     33         this.template = template;
     34         OutputPath = String.Empty;
     35         strategy = ManagementStrategy.Create(host);
     36     }
     37 
     38     public void StartBlock(String name) {
     39         currentBlock = new Block { Name = name, Start = template.Length };
     40     }
     41 
     42     public void StartFooter() {
     43         footerBlock.Start = template.Length;
     44     }
     45 
     46     public void EndFooter() {
     47         footerBlock.Length = template.Length - footerBlock.Start;
     48     }
     49 
     50     public void StartHeader() {
     51         headerBlock.Start = template.Length;
     52     }
     53 
     54     public void EndHeader() {
     55         headerBlock.Length = template.Length - headerBlock.Start;
     56     }    
     57 
     58     public void EndBlock() {
     59         currentBlock.Length = template.Length - currentBlock.Start;
     60         blocks.Add(currentBlock);
     61     }
     62 
     63     public void Process(bool split) {
     64         String header = template.ToString(headerBlock.Start, headerBlock.Length);
     65         String footer = template.ToString(footerBlock.Start, footerBlock.Length);
     66         blocks.Reverse();
     67         foreach(Block block in blocks) {
     68             String fileName = Path.Combine(OutputPath, block.Name);
     69             if (split) {
     70                 String content = header + template.ToString(block.Start, block.Length) + footer;
     71                 strategy.CreateFile(fileName, content);
     72                 template.Remove(block.Start, block.Length);
     73             } else {
     74                 strategy.DeleteFile(fileName);
     75             }
     76         }
     77     }
     78 }
     79 
     80 class ManagementStrategy
     81 {
     82     internal static ManagementStrategy Create(ITextTemplatingEngineHost host) {
     83         return (host is IServiceProvider) ? new VSManagementStrategy(host) : new ManagementStrategy(host);
     84     }
     85 
     86     internal ManagementStrategy(ITextTemplatingEngineHost host) { }
     87 
     88     internal virtual void CreateFile(String fileName, String content) {
     89         File.WriteAllText(fileName, content);
     90     }
     91 
     92     internal virtual void DeleteFile(String fileName) {
     93         if (File.Exists(fileName))
     94             File.Delete(fileName);
     95     }
     96 }
     97 
     98 class VSManagementStrategy : ManagementStrategy
     99 {
    100     private EnvDTE.ProjectItem templateProjectItem;
    101 
    102     internal VSManagementStrategy(ITextTemplatingEngineHost host) : base(host) {
    103         IServiceProvider hostServiceProvider = (IServiceProvider)host;
    104         if (hostServiceProvider == null)
    105             throw new ArgumentNullException("Could not obtain hostServiceProvider");
    106 
    107         EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
    108         if (dte == null)
    109             throw new ArgumentNullException("Could not obtain DTE from host");
    110 
    111         templateProjectItem = dte.Solution.FindProjectItem(host.TemplateFile);
    112     }
    113 
    114     internal override void CreateFile(String fileName, String content) {
    115         base.CreateFile(fileName, content);
    116         ((EventHandler)delegate { templateProjectItem.ProjectItems.AddFromFile(fileName); }).BeginInvoke(null, null, null, null);
    117     }
    118 
    119     internal override void DeleteFile(String fileName) {
    120         ((EventHandler)delegate { FindAndDeleteFile(fileName); }).BeginInvoke(null, null, null, null);
    121     }
    122 
    123     private void FindAndDeleteFile(String fileName) {
    124         foreach(EnvDTE.ProjectItem projectItem in templateProjectItem.ProjectItems) {
    125             if (projectItem.get_FileNames(0) == fileName) {
    126                 projectItem.Delete();
    127                 return;
    128             }
    129         }
    130     }
    131 }#>
    Dump2MultipleFiles.ttinclude

     

     

    指定要输出的文件名

    像下面这样,即可指定多个输出文件了。

     

     1 <#@ template debug="false" hostspecific="true" language="C#" #>
     2 <#@ output extension=".cs" #>
     3 <#@ include file=".Dump2MultipleFiles.ttinclude" #>
     4 <# string ShaderName = "SomeShader"; #>
     5 <# string ClassName = ShaderName + "Renderer"; #>
     6 <# string VertexShaderName = ShaderName + "Vert"; #>
     7 <# string FragmentShaderName = ShaderName + "Frag"; #>
     8 
     9 <# var manager = new Manager(Host, GenerationEnvironment, true) { OutputPath = Path.GetDirectoryName(Host.TemplateFile)}; #>
    10 <#
    11     // 下述内容写入ShaderName + ".cs"文件
    12 manager.StartBlock(ShaderName + ".cssl.cs");
    13 #>
    14 namespace CSharpShaders
    15 {
    16     class <#= VertexShaderName #> : VertexCSShaderCode
    17     { 
    18     }
    19 }
    20 <#
    21     // 上述内容写入ShaderName + ".cs"文件
    22     manager.EndBlock();
    23 #>
    24 <#
    25     // 下述内容写入ClassName + ".cs"文件
    26     manager.StartBlock(ClassName + ".cs");
    27 #>
    28 namespace ShaderLab
    29 {
    30     public class <#= ClassName #> : RendererBase
    31     {
    32     }
    33 }
    34 
    35 <#
    36     // 上述内容写入ClassName + ".cs"文件
    37     manager.EndBlock();
    38 
    39     // 最后要写上这句话
    40     manager.Process(true);
    41 #>

    总结

    本篇使用T4模板生成多个代码文件,其方法是通用的。

  • 相关阅读:
    C/C++ 语言中的表达式求值
    C++中delete与delete[]
    特殊数据类型成员变量的初始化
    C++中的new
    C++数组名解析
    C++中的位拷贝和值拷贝
    while(cin>>s)退出问题
    C++继承中的虚析构函数
    C++的IO标准库介绍
    C++一道面试题(atexit)
  • 原文地址:https://www.cnblogs.com/bitzhuwei/p/CSharpGL-12-T4-generated-CSSL-and-Renderer.html
Copyright © 2011-2022 走看看