1 module ppc.shader;
2 import ppc;
3 import ppc.exceptions;
4 
5 import std.conv;
6 import std.bitmanip;
7 
8 public class ShaderFactory : ContentFactory {
9 	public this() {
10 		super(TypeId.Shader);
11 	}
12 
13 	public override Content Construct(ubyte[] data) {
14 		return new Shader(data);
15 	}
16 }
17 
18 public enum ShaderType : ubyte {
19 	SPIRV,
20 	GLSL,
21 	PPSL
22 }
23 
24 public enum CodeType : ubyte {
25 	SPIRVFullShader,
26 	PPSLFullShader,
27 	Vertex,
28 	Geometry,
29 	Fragment
30 }
31 
32 public class ShaderCode {
33 	public CodeType Type;
34 	public ubyte[] Code;
35 	public @property string CodeString() { return cast(string)Code; }
36 	public @property void CodeString(string value) { Code = cast(ubyte[])value; }
37 
38 	public this(CodeType type) {
39 		this.Type = type;
40 		this.Code = [];
41 	}
42 
43 	public this(CodeType type, ubyte[] code) {
44 		this.Type = type;
45 		this.Code = code;
46 	}
47 }
48 
49 public class Shader : Content {
50 
51 	public ShaderType Type;
52 	public ShaderCode[] Code;
53 
54 	public this(string name) {
55 		super(TypeId.Shader, name);
56 	}
57 
58 	public this(ubyte[] data) {
59 		super(data);
60 		this.Type = cast(ShaderType)this.data[0];
61 		bool done = false;
62 		int i = 1;
63 		while (!done) {
64 			// Set Code Type Header.
65 			CodeType t = cast(CodeType)this.data[i];
66 			i++;
67 
68 			// Set Length Header.
69 			ubyte[4] len_i = this.data[i..i+4];
70 			int length = bigEndianToNative!int(len_i);
71 			i += 4;
72 
73 			if (length == 0) throw new InvalidHeaderSizeException("Shader [Infinite loading loop!]");
74 
75 			// Set Shader Code.
76 			ubyte[] d = this.data[i..i+length];
77 			i += length;
78 			Code.length++;
79 			Code[Code.length-1] = new ShaderCode(t, d);
80 
81 			//Finish off loading the shader code, if no more data is left.
82 			if (i+1 >= this.data.length) done = true;
83 		}
84 	}
85 	
86 	public override void Convert(ubyte[] data) {
87 		// Do Nothing, nonconvertible type for now
88 	}
89 
90 	public void Add(ShaderCode code) {
91 		this.Code.length++;
92 		this.Code[this.Code.length-1] = code;
93 	}
94 
95 	public override ubyte[] Compile() {
96 		ubyte[] data = [cast(ubyte)Type];
97 		foreach(ShaderCode c; Code) {
98 			
99 			//Add Type header for shader code.
100 			data.length += 1;
101 			ulong s = data.length-1;
102 			data[s] = cast(ubyte)c.Type;
103 			s++;
104 
105 			//Add Size header for shader code.
106 			data.length += 4;
107 			int len_i = cast(int)c.Code.length;
108 			ubyte[] len = nativeToBigEndian(len_i);
109 			s += 4;
110 
111 			//Add shader code.
112 			data.length += c.Code.length;
113 			for (int i = 0; i < c.Code.length; i++) {
114 				data[s+i] = c.Code[i];
115 			}
116 		}
117 		return data;
118 	}
119 }