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模板生成多个代码文件,其方法是通用的。

CSharpGL(12)用T4模板生成CSSL及其renderer代码的更多相关文章

  1. MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    前言 经过前面EF的<第一篇>与<第二篇>,我们的数据层功能已经较为完善了,但有不少代码相似度较高,比如负责实体映射的 EntityConfiguration,负责仓储操作的I ...

  2. [转]MVC实用架构设计(三)——EF-Code First(3):使用T4模板生成相似代码

    本文转自:http://www.cnblogs.com/guomingfeng/p/mvc-ef-t4.html 〇.目录 一.前言 二.工具准备 三.T4代码生成预热 (一) 单文件生成:Hello ...

  3. 使用T4模板生成不同部署环境下的配置文件

    在开发企业级应用的时候,通常会有不同的开发环境,比如有开发环境,测试环境,正式环境,生产环境等.在一份代码部署到不同环境的时候,不同环境的配置文件可能需要根据目标环境不同而不同.比如在开发环境中,数据 ...

  4. 从零开始编写自己的C#框架(12)——T4模板在逻辑层中的应用(一)(附源码)

    对于T4模板很多朋友都不太熟悉,它在项目开发中,会帮我们减轻很大的工作量,提升我们的开发效率,减少出错概率.所以学好T4模板的应用,对于开发人员来说是非常重要的. 园子里对于T4模板的介绍与资料已经太 ...

  5. EF CodeFirst 使用T4模板 生成文件

    小编是个实用主义者,并没有深入的去理解T4的原理.只是根据自己的需求,在博客园里的前辈哪里找的资料,结合自己的理解,在项目中使用了T4模板. 最近的项目用了他,很方便,节省了不少代码量. 想利用T4做 ...

  6. 利用T4模板生成ASP.NET Core控制器的构造函数和参数

    前言 在ASP.NET Core中引入了DI,并且通过构造函数注入参数,控制器中会大量使用DI注入各种的配置参数,如果配置注入的参数比较多,而且各个控制器需要的配置参数都基本一样的话,那么不断重复的复 ...

  7. Visual Studio 2013 EF5实体数据模型 EDMX 使用 T4模板生成后使用 ObjectContext对象

    Visual Studio 2013 EF5实体数据模型 EDMX 使用 T4模板生成后的继承对象为DbContext,以前的熟悉的ObjectContext对象不见了,当然使用ObjectConte ...

  8. T4模板生成不同部署环境下的配置文件

    使用T4模板生成不同部署环境下的配置文件 在开发企业级应用的时候,通常会有不同的开发环境,比如有开发环境,测试环境,正式环境,生产环境等.在一份代码部署到不同环境的时候,不同环境的配置文件可能需要根据 ...

  9. 使用T4模板生成MySql数据库实体类

    注:本文系作者原创,但可随意转载. 现在呆的公司使用的数据库几乎都是MySQL.编程方式DatabaseFirst.即先写数据库设计,表设计按照规范好的文档写进EXCEL里,然后用公司的宏,生成建表脚 ...

随机推荐

  1. 如何用百度MIP快速搭建体验友好的移动页面

    在读这篇文章之前,请确定你已经了解MIP定义及加速原理.如果不确定的话,可以到MIP官网了解. 改造前期准备和注意事项: 你可以选择直接将原先的移动站点直接改成MIP站,也可以单独再做一套MIP站点与 ...

  2. C++中的时间函数

    C++获取时间函数众多,何时该用什么函数,拿到的是什么时间?该怎么用?很多人都会混淆. 本文是本人经历了几款游戏客户端和服务器开发后,对游戏中时间获取的一点总结. 最早学习游戏客户端时,为了获取最精确 ...

  3. android studio 使用 jni 编译 opencv 完整实例 之 图像边缘检测!从此在andrid中自由使用 图像匹配、识别、检测

    目录: 1,过程感慨: 2,运行环境: 3,准备工作: 4,编译 .so 5,遇到的关键问题及其解决方法 6,实现效果截图. (原创:转载声明出处:http://www.cnblogs.com/lin ...

  4. iOS开源项目周报1215

    由OpenDigg 出品的iOS开源项目周报第一期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. PY ...

  5. iOS7 NavigationController 手势问题

    在iOS7中,如果使用了UINavigationController,那么系统自带的附加了一个从屏幕左边缘开始滑动可以实现pop的手势.但是,如果自定义了navigationItem的leftBarB ...

  6. 在VMware上安装CentOS -7

    1.下载好VMware 2.准备好CentOS的镜像文件 3.打开VMware创建新的虚拟机 选择自定义高级后按下一步 继续下一步 选择稍后安装操作系统 客户机操作系统选择Linux,版本选择Cent ...

  7. Markdown学习笔记

    分为两步: 1.阅读Markdown中文官网的文档 2.下载MarkdownPad2将中文官网中文档的例子敲一遍,其中Markdownpad2为官网中推荐的编辑器 备注: 如果只看中文官网文档,不边看 ...

  8. CentOS7 + mono +Jexus 环境的搭建

    CentOS7的安装和配置 1,从http://www.centos.org/下载CentOS7的镜像,并在VMWare中创建该镜像的虚拟机,为方便操作,把虚拟机的网络连接设置为桥接模式:在安装过程中 ...

  9. Glide源码导读

    最近比较无聊,为了找点事干,就花了两天时间把Glide的源码大概看了一下.刚开始看Glide的源码头脑还是比较乱的,因为作者引入了几个概念,又大量用了泛型,如果不了解这些概念读起代码来就比较痛苦,我也 ...

  10. Entity Framework 6 Recipes 2nd Edition(13-3)译 -> 为一个只读的访问获取实体

    问题 你想有效地获取只是用来显示不会更新的操作的实体.另外,你想用CodeFirst的方式来实现 解决方案 一个非常常见行为,尤其是网站,就是只是让用户浏览数据.大多数情况下,用户不会更新数据.在这种 ...