1
+ from enum import Enum , Flag
2
+ from typing import BinaryIO , Union
3
+
4
+ from binreader import BinaryReader
5
+
6
+
7
+ class SerializeFlags (Flag ):
8
+ Normal = 0
9
+ Dynamic = 1
10
+ Nullable = 2
11
+
12
+ class EffectShaderType (Enum ):
13
+ Vertex = 0
14
+ Hull = 1
15
+ Domain = 2
16
+ Geometry = 3
17
+ Pixel = 4
18
+ Compute = 5
19
+
20
+ class EffectCompilerFlags (Flag ):
21
+ Debug = 1
22
+ SkipValidation = 2
23
+ SkipOptimization = 4
24
+ PackMatrixRowMajor = 8
25
+ PackMatrixColumnMajor = 16
26
+ PartialPrecision = 32
27
+ AvoidFlowControl = 512
28
+ PreferFlowControl = 1024
29
+ EnableStrictness = 2048
30
+ EnableBackwardsCompatibility = 4096
31
+ IeeeStrictness = 8192
32
+ OptimizationLevel0 = 16384
33
+ OptimizationLevel1 = 0
34
+ OptimizationLevel2 = 49152
35
+ OptimizationLevel3 = 32768
36
+ WarningsAreErrors = 262144
37
+ Empty = 0
38
+
39
+ class FeatureLevel (Enum ):
40
+ Level_9_1 = 37120
41
+ Level_9_2 = 37376
42
+ Level_9_3 = 37632
43
+ Level_10_0 = 40960
44
+ Level_10_1 = 41216
45
+ Level_11_0 = 45056
46
+
47
+ class EffectParameterClass (Enum ):
48
+ Scalar = 0
49
+ Vector = 1
50
+ MatrixRows = 2
51
+ MatrixColumns = 3
52
+ Object = 4
53
+ Struct = 5
54
+ InterfaceClass = 6
55
+ InterfacePointer = 7
56
+
57
+ class EffectParameterType (Enum ):
58
+ Void = 0
59
+ Bool = 1
60
+ Int = 2
61
+ Float = 3
62
+ String = 4
63
+ Texture = 5
64
+ Texture1D = 6
65
+ Texture2D = 7
66
+ Texture3D = 8
67
+ TextureCube = 9
68
+ Sampler = 10
69
+ Sampler1D = 11
70
+ Sampler2D = 12
71
+ Sampler3D = 13
72
+ SamplerCube = 14
73
+ Pixelshader = 15
74
+ Vertexshader = 16
75
+ Pixelfragment = 17
76
+ Vertexfragment = 18
77
+ UInt = 19
78
+ UInt8 = 20
79
+ Geometryshader = 21
80
+ Rasterizer = 22
81
+ Depthstencil = 23
82
+ Blend = 24
83
+ Buffer = 25
84
+ ConstantBuffer = 26
85
+ TextureBuffer = 27
86
+ Texture1DArray = 28
87
+ Texture2DArray = 29
88
+ Rendertargetview = 30
89
+ Depthstencilview = 31
90
+ Texture2DMultisampled = 32
91
+ Texture2DMultisampledArray = 33
92
+ TextureCubeArray = 34
93
+ Hullshader = 35
94
+ Domainshader = 36
95
+ InterfacePointer = 37
96
+ Computeshader = 38
97
+ Double = 39
98
+ RWTexture1D = 40
99
+ RWTexture1DArray = 41
100
+ RWTexture2D = 42
101
+ RWTexture2DArray = 43
102
+ RWTexture3D = 44
103
+ RWBuffer = 45
104
+ ByteAddressBuffer = 46
105
+ RWByteAddressBuffer = 47
106
+ StructuredBuffer = 48
107
+ RWStructuredBuffer = 49
108
+ AppendStructuredBuffer = 50
109
+ ConsumeStructuredBuffer = 51
110
+
111
+ class WrappedBinaryReader (BinaryReader ):
112
+ def __init__ (self , buf : BinaryIO , endian : str = "<" ) -> None :
113
+ super ().__init__ (buf , endian )
114
+
115
+ def is_serialize_null (self , flags : SerializeFlags = SerializeFlags .Nullable ) -> bool :
116
+ if (flags & SerializeFlags .Nullable ) != SerializeFlags .Normal :
117
+ # read a byte
118
+ aByte = self .read_byte ()
119
+
120
+ # 1 stores a reference, 2 gets this reference
121
+ if aByte == 1 :
122
+ print ("is_serialize_null: 1" )
123
+ elif aByte == 2 :
124
+ raise Exception ("length 2 is not supported" )
125
+
126
+ # if 0, string is null
127
+ return aByte == 0
128
+
129
+ return False
130
+
131
+ def read_7bit_encoded_int (self ) -> int :
132
+ value = 0
133
+ shift = 0
134
+ while True :
135
+ byte_value = ord (self .read (1 ))
136
+ value |= (byte_value & 0x7F ) << shift
137
+ shift += 7
138
+ if (byte_value & 0x80 ) == 0 :
139
+ break
140
+ return value
141
+
142
+ def serialize_string (self , flags = SerializeFlags .Normal ) -> Union [str , None ]:
143
+ if self .is_serialize_null (flags = flags ):
144
+ return None
145
+
146
+ # read the size
147
+ size = self .read_7bit_encoded_int ()
148
+ # read the string
149
+ return self .read (size ).decode ("utf-8" )
150
+
151
+ def serialize_bytes (self , flags = SerializeFlags .Normal ) -> bytes :
152
+ if self .is_serialize_null (flags = flags ):
153
+ return None
154
+
155
+ # read the size
156
+ size = self .read_7bit_encoded_int ()
157
+ # read the bytes
158
+ return self .read (size )
159
+
160
+ def serialize_class_array (self , class_type : type ) -> object :
161
+ if self .is_serialize_null (flags = SerializeFlags .Normal ):
162
+ return None
163
+
164
+ # read the number of classes
165
+ count = self .read_7bit_encoded_int ()
166
+ return [class_type (self ) for i in range (count )]
167
+
168
+ class FourCC :
169
+ @classmethod
170
+ def calculate (self , code ):
171
+ """
172
+ Create a FourCC code from a four-character string.
173
+ """
174
+ if len (code ) != 4 :
175
+ raise ValueError ("FourCC code must be a four-character string." )
176
+
177
+ fourcc = 0
178
+ for i , char in enumerate (code ):
179
+ fourcc += ord (char ) << (8 * i )
180
+
181
+ return fourcc
182
+
183
+ class Chunk :
184
+ id : int
185
+ index_end : int
186
+ reader : WrappedBinaryReader
187
+
188
+ def __init__ (self , id : str , reader : WrappedBinaryReader ):
189
+ self .id = FourCC .calculate (id )
190
+ self .reader = reader
191
+
192
+ # read the magic from the file
193
+ magic = reader .read_int32 ()
194
+ if magic != self .id :
195
+ raise ValueError ("Invalid Chunk Magic." )
196
+
197
+ # read the chunk end index
198
+ self .index_end = reader .read_int32 ()
199
+
200
+ class TKFX (Chunk ):
201
+ version : int
202
+
203
+ def __init__ (self , reader : WrappedBinaryReader ):
204
+ super ().__init__ ("TKFX" , reader )
205
+ self .version = reader .read_int32 ()
206
+
207
+ # hard coded version check
208
+ if self .version != 257 :
209
+ raise ValueError ("Invalid TKFX version." )
210
+
211
+ class SHDRShaderSignatureSemantic :
212
+ name : str
213
+ index : int
214
+ register : int
215
+ system_value_type : int
216
+ component_type : int
217
+ usage_mask : int
218
+ read_write_mask : int
219
+ stream : int
220
+
221
+ def __init__ (self , reader : WrappedBinaryReader ):
222
+ self .name = reader .serialize_string ()
223
+ self .index = reader .read_byte ()
224
+ self .register = reader .read_byte ()
225
+ self .system_value_type = reader .read_byte ()
226
+ self .component_type = reader .read_byte ()
227
+ self .usage_mask = reader .read_byte ()
228
+ self .read_write_mask = reader .read_byte ()
229
+ self .stream = reader .read_byte ()
230
+
231
+ def __repr__ (self ) -> str :
232
+ return f"SHDRShaderSignatureSemantic(name={ self .name } , index={ self .index } , register={ self .register } , system_value_type={ self .system_value_type } , component_type={ self .component_type } , usage_mask={ self .usage_mask } , read_write_mask={ self .read_write_mask } , stream={ self .stream } )"
233
+
234
+ class SHDRShaderSignature :
235
+ semantics : list [SHDRShaderSignatureSemantic ]
236
+ bytecode : bytes
237
+ hashcode : int
238
+
239
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
240
+ self .semantics = reader .serialize_class_array (SHDRShaderSignatureSemantic )
241
+ # read bytecode
242
+ self .bytecode = reader .serialize_bytes (flags = SerializeFlags .Nullable )
243
+ # read hashcode
244
+ self .hashcode = reader .read_int32 ()
245
+
246
+ def __repr__ (self ) -> str :
247
+ return f"SHDRShaderSignature(semantics={ self .semantics } , bytecode={ self .bytecode } , hashcode={ self .hashcode } )"
248
+
249
+ class Base :
250
+ name : str
251
+ parameter_class : EffectParameterClass
252
+ parameter_type : EffectParameterType
253
+
254
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
255
+ self .name = reader .serialize_string ()
256
+ self .parameter_class = EffectParameterClass (reader .read_byte ())
257
+ self .parameter_type = EffectParameterType (reader .read_byte ())
258
+
259
+ def __repr__ (self ) -> str :
260
+ return f"Base(name={ self .name } , parameter_class={ self .parameter_class } , parameter_type={ self .parameter_type } )"
261
+
262
+ class ValueTypeParameter (Base ):
263
+ offset : int
264
+ count : int
265
+ size : int
266
+ row_count : int
267
+ column_count : int
268
+ default_value : bytes
269
+
270
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
271
+ super ().__init__ (reader )
272
+ self .offset = reader .read_7bit_encoded_int ()
273
+ self .count = reader .read_7bit_encoded_int ()
274
+ self .size = reader .read_7bit_encoded_int ()
275
+ self .row_count = reader .read_byte ()
276
+ self .column_count = reader .read_byte ()
277
+ self .default_value = reader .serialize_bytes (flags = SerializeFlags .Nullable )
278
+
279
+ def __repr__ (self ) -> str :
280
+ return f"ValueTypeParameter(name={ self .name } , class={ self .parameter_class } , type={ self .parameter_type } , offset={ self .offset } , count={ self .count } , size={ self .size } , row_count={ self .row_count } , column_count={ self .column_count } , default_value={ self .default_value } )"
281
+
282
+ class ConstantBuffer :
283
+ name : str
284
+ size : int
285
+ parameters : list [ValueTypeParameter ]
286
+
287
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
288
+ self .name = reader .serialize_string ()
289
+ self .size = reader .read_7bit_encoded_int ()
290
+
291
+ # read an array of parameters
292
+ self .parameters = reader .serialize_class_array (ValueTypeParameter )
293
+
294
+ def __repr__ (self ) -> str :
295
+ return f"ConstantBuffer(name={ self .name } , size={ self .size } , parameters={ self .parameters } )"
296
+
297
+ class ResourceParameter (Base ):
298
+ slot : int
299
+ count : int
300
+
301
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
302
+ super ().__init__ (reader )
303
+ self .slot = reader .read_byte ()
304
+ self .count = reader .read_byte ()
305
+
306
+ def __repr__ (self ) -> str :
307
+ return f"ResourceParameter(name={ self .name } , class={ self .parameter_class } , type={ self .parameter_type } , slot={ self .slot } , count={ self .count } )"
308
+
309
+ class SHDRShader :
310
+ name : str
311
+ shader_type : EffectShaderType
312
+ compiler_flags : EffectCompilerFlags
313
+ feature_level : FeatureLevel
314
+ bytecode : bytes
315
+ hashcode : int
316
+ input_signature : SHDRShaderSignature
317
+ output_signature : SHDRShaderSignature
318
+ constant_buffers : list [ConstantBuffer ]
319
+ resource_parameters : list [ResourceParameter ]
320
+
321
+ def __init__ (self , reader : WrappedBinaryReader ) -> None :
322
+ self .name = reader .serialize_string (flags = SerializeFlags .Nullable )
323
+ # read the shader type
324
+ self .shader_type = EffectShaderType (reader .read_byte ())
325
+ # read compiler flags
326
+ self .compiler_flags = EffectCompilerFlags (reader .read_int32 ())
327
+ # read feature level
328
+ self .feature_level = FeatureLevel (reader .read_int32 ())
329
+ # read bytecode
330
+ self .bytecode = reader .serialize_bytes ()
331
+ # read hashcode
332
+ self .hashcode = reader .read_int32 ()
333
+ # read input signature
334
+ self .input_signature = SHDRShaderSignature (reader )
335
+ # read output signature
336
+ self .output_signature = SHDRShaderSignature (reader )
337
+ # read constant buffers
338
+ self .constant_buffers = reader .serialize_class_array (ConstantBuffer )
339
+ # read resource parameters
340
+ self .resource_parameters = reader .serialize_class_array (ResourceParameter )
341
+
342
+ def __repr__ (self ) -> str :
343
+ return f"SHDRShader(name={ self .name } , shader_type={ self .shader_type } , compiler_flags={ self .compiler_flags } , feature_level={ self .feature_level } , bytecode={ self .bytecode } , hashcode={ self .hashcode } , input_signature={ self .input_signature } , output_signature={ self .output_signature } , constant_buffers={ self .constant_buffers } , resource_parameters={ self .resource_parameters } )"
344
+
345
+ class SHDR (Chunk ):
346
+ def __init__ (self , reader : WrappedBinaryReader ):
347
+ super ().__init__ ("SHDR" , reader )
348
+
349
+ # read an array of shaders
350
+ num_shaders = self .reader .read_7bit_encoded_int ()
351
+ print ("Shader Count: " + str (num_shaders ))
352
+ for i in range (num_shaders ):
353
+ shader = SHDRShader (self .reader )
354
+ print (shader )
355
+
356
+
357
+ with open ("C:\\ Run8Studios\\ Run8 Train Simulator V3\\ Content\\ Shaders\\ Avatar.tkb" , "rb" ) as f :
358
+ reader = WrappedBinaryReader (f )
359
+ tkfx = TKFX (reader )
360
+ shdr = SHDR (reader )
0 commit comments