forked from niacdoial/blemd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTex1.py
205 lines (189 loc) · 6.74 KB
/
Tex1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
#! /usr/bin/python3
import re
import logging
log = logging.getLogger('bpy.ops.import_mesh.bmd.tex1')
class ImageHeader:
# <variable data>
# -- Image*
# <variable name>
# -- std::string
#
# from gx.h:
# 0: clamp to edge
# 1: repeat
# 2: mirror
# # <variable wrapS>
# <variable wrapT>
# -- u8
# --TODO: unknown fields
def __init__(self): # GENERATED!
pass
# ------------------------------------------------------------------------------------------------
class Image:
"""# <variable format>
# -- int
# <variable width>
# <variable height>
# -- int
# <variable mipmaps>
# --std::vector<u8*> points into imageData
# <variable sizes>
# -- std::vector<int> image data size for each mipmap
# <variable imageData>
# -- std::vector<u8>
#
# //NOTE: palettized images are converted
# //to non-palettized images during load time,
# //i4 and i4a4 are converted to i8 and i8a8
# //(i8a8 is then converted to a8i8 for opengl),
# //r5g5b5a3 and r5g6b5 to rgba8 (actually, to agbr8,
# //that is rgba8 backwards - for opengl. rgba8
# //is converted to agbr8 as well).
# //(that is, only formats 1, 3, 6 and 14 are
# //used after conversion)
# # --TODO: gl image conversions (rgba -> abgr, ia -> ai
# --somewhere else?)
# --TODO: this is temporary and belongs somewhere else:
# <variable texId>
# -- unsigned int """
def __init__(self): # GENERATED!
self.mipmaps = []
self.sizes = []
self.imageData = []
# ------------------------------------------------------------------------------------------------
# -- header format for 'bmd3' files, seems to be slightly different for 'jpa1'
class Tex1Header:
"""# <variable tag>
# --char [4] 'TEX1'
# <variable sizeOfSection>
# -- u32
# <variable numImages>
# -- u16
# <variable unknown>
# -- u16 padding, usually 0xffff
# <variable textureHeaderOffset>
# -- u32numImages bti image headers are stored here (see bti spec)
# --note: several image headers may point to same image data
# --offset relative to Tex1Header start
# <variable stringTableOffset>
# -- u32stores one filename for each image (TODO: details on stringtables)
# --offset relative to Tex1Header start
# <function>"""
def __init__(self): # GENERATED!
self.tag = None
self.sizeOfSection = None
self.numImages = 0
self.unknown = None
self.textureHeaderOffset = None
self.stringTableOffset = None
def LoadData(self, br):
self.tag = br.ReadFixedLengthString(4)
self.sizeOfSection = br.ReadDWORD()
self.numImages = br.ReadWORD()
self.unknown = br.ReadWORD()
self.textureHeaderOffset = br.ReadDWORD()
self.stringTableOffset = br.ReadDWORD()
# ------------------------------------------------------------------------------------------------
class TextureHeader:
"""# <variable format>
# -- u8data format - seems to match tpl's format (see yagcd)
# <variable unknown>
# -- u8
# <variable width>
# -- u16
# <variable height>
# -- u16
#
# from gx.h:
# 0: clamp to edge
# 1: repeat
# 2: mirror
# # <variable wrapS>
# -- u8
# <variable wrapT>
# -- u8
# <variable unknown3>
# -- u8
# <variable paletteFormat>
# -- u8 palette format - matches tpl palette format (-> yagcd)
# <variable paletteNumEntries>
# -- u16
# <variable paletteOffset>
# -- u32 palette data
# <variable unknown5>
# -- u32
# <variable unknown6>
# -- u16 prolly two u8s, first is 5 or 1, second 1 most of the time
# <variable unknown7>
# -- u16 0 most of the time, sometimes 0x10, 0x18, 0x20, 0x28
# <variable mipmapCount>
# -- u8
# <variable unknown8>
# -- u8
# <variable unknown9>
# -- u16
# <variable dataOffset>
# -- u32 image data
# --some of the unknown data could be render state?
# --(lod bias, min/mag filter, clamp s/t, ...)
# <function>"""
def __init__(self): # GENERATED!
pass
def LoadData(self, br):
self.format = br.GetByte()
self.unknown = br.GetByte()
self.width = br.ReadWORD()
self.height = br.ReadWORD()
self.wrapS = br.GetByte()
self.wrapT = br.GetByte()
self.unknown3 = br.GetByte()
self.paletteFormat = br.GetByte()
self.paletteNumEntries = br.ReadWORD()
self.paletteOffset = br.ReadDWORD()
self.unknown5 = br.ReadDWORD()
self.unknown6 = br.ReadWORD()
self.unknown7 = br.ReadWORD()
self.mipmapCount = br.GetByte()
self.unknown8 = br.GetByte()
self.unknown9 = br.ReadWORD()
self.dataOffset = br.ReadDWORD()
# ------------------------------------------------------------------------------------------------
class Tex1:
# --imageHeaders = #(), -- std::vector<ImageHeader>
# <variable texHeaders>
# <variable stringtable>
# --because several image headers might point to the
# --same image data, this data is stored
# --separately to save some memory
# --(this way only about 1/6 of the memory required
# --otherwise is used)
# -- images = #(), -- std::vector<Image >
# <function>
def __init__(self): # GENERATED!
self.texHeaders = []
def LoadData(self, br):
tex1Offset = br.Position()
# -- read textureblock header
h = Tex1Header()
h.LoadData(br)
# -- read self.stringtable
self.stringtable = br.ReadStringTable(tex1Offset + h.stringTableOffset) # readStringtable(tex1Offset + h.stringTableOffset, f, self.stringtable);
for i in range(len(self.stringtable)):
if re.search(r'[\\/]', self.stringtable[i]):
log.critical('weird characters found in image stringtable. THIS MIGHT HAVE BEEN AN ATTACK')
raise KeyboardInterrupt('\n\n>>>>>>POSSIBLE ATTACK. TERMINATING. <<<<<<')
if len(self.stringtable) != h.numImages:
if common.GLOBALS.PARANOID:
raise ValueError("tex1: number of strings doesn't match number of images")
else:
for i in range(h.numImages - len(self.stringtable)):
self.stringtable.append('unknown name %d' %i)
# -- read all image headers before loading the actual image
# -- data, because several headers can refer to the same data
br.SeekSet(tex1Offset + h.textureHeaderOffset)
self.texHeaders = []
imageOffsets = []
for _ in range(h.numImages):
texHeader = TextureHeader()
texHeader.LoadData(br)
self.texHeaders.append(texHeader)