-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathmod_dds_header.lua
358 lines (303 loc) · 9.34 KB
/
mod_dds_header.lua
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
assert(_VERSION == "Lua 5.3")
-- DDS header [32]
_fourcc = 1; _size = 2; _flags = 3; _height = 4
_width = 5; _pitch = 6; _depth = 7; _mipmaps = 8
-- reserved [44]
-- 9 10 11 12
-- 13 14 15 16
-- 17 18 19
-- DDSPixelFormat [32]
_psize = 20; _pflags = 21; _pfourcc = 22; _pbpp = 23
_prmask = 24; _pgmask = 25; _pbmask = 26; _pamask = 27
-- DDSCaps [16]
_caps1 = 28; _caps2 = 29; _caps3 = 30; _caps4 = 31
--
_notused = 32
-- DDSHeader10 [20]
_dxgiFmt = 33; _resDim = 34; _miscFlag = 35; _arraySize = 36
_reserved = 37
local function MAKEFOURCC(fourcc)
-- local a, b, c, d = string.byte(fourcc, 1, 4)
-- return a | (b << 8) | (c << 16) | (d << 24)
return string.unpack("<I", fourcc)
end
FOURCC_DDS = MAKEFOURCC("DDS ")
FOURCC_DXT1 = MAKEFOURCC("DXT1")
FOURCC_DXT2 = MAKEFOURCC("DXT2")
FOURCC_DXT3 = MAKEFOURCC("DXT3")
FOURCC_DXT4 = MAKEFOURCC("DXT4")
FOURCC_DXT5 = MAKEFOURCC("DXT5")
FOURCC_RXGB = MAKEFOURCC("RXGB")
FOURCC_ATI1 = MAKEFOURCC("ATI1")
FOURCC_ATI2 = MAKEFOURCC("ATI2")
FOURCC_A2XY = MAKEFOURCC("A2XY")
FOURCC_DX10 = MAKEFOURCC("DX10")
Format_RGB = 0
Format_RGBA = Format_RGB
-- DX9 formats.
Format_DXT1 = 1
Format_DXT1a = 2 -- DXT1 with binary alpha.
Format_DXT3 = 3
Format_DXT5 = 4
Format_DXT5n = 5 -- Compressed HILO: R=1, G=y, B=0, A=x
-- DX10 formats.
Format_BC1 = Format_DXT1
Format_BC1a = Format_DXT1a
Format_BC2 = Format_DXT3
Format_BC3 = Format_DXT5
Format_BC3n = Format_DXT5n
Format_BC4 = 6 -- ATI1
Format_BC5 = 7 -- 3DC, ATI2
DDSD_CAPS = 0x00000001
DDSD_HEIGHT = 0x00000002
DDSD_WIDTH = 0x00000004
DDSD_PITCH = 0x00000008
DDSD_PIXELFORMAT = 0x00001000
DDSD_MIPMAPCOUNT = 0x00020000
DDSD_LINEARSIZE = 0x00080000
DDSD_DEPTH = 0x00800000
DDSCAPS_COMPLEX = 0x00000008
DDSCAPS_TEXTURE = 0x00001000
DDSCAPS_MIPMAP = 0x00400000
DDSCAPS2_VOLUME = 0x00200000
DDSCAPS2_CUBEMAP = 0x00000200
DDSCAPS2_CUBEMAP_ALL_FACES = 0x0000FC00
DDPF_ALPHAPIXELS = 0x00000001
DDPF_ALPHA = 0x00000002
DDPF_FOURCC = 0x00000004
DDPF_RGB = 0x00000040
DDPF_NORMAL = 0x80000000 -- Custom nv flag
-- enum DXGI_FORMAT
DXGI_FORMAT_UNKNOWN = 0
-- enum D3D10_RESOURCE_DIMENSION
D3D10_RESOURCE_DIMENSION_UNKNOWN = 0
D3D10_RESOURCE_DIMENSION_BUFFER = 1
D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2
D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3
D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4
-- init
DDSHeader = {}
function DDSHeader:new()
self[_fourcc] = FOURCC_DDS
self[_size] = 124
self[_flags] = DDSD_CAPS | DDSD_PIXELFORMAT
self[_height] = 0
self[_width] = 0
self[_pitch] = 0
self[_depth] = 0
self[_mipmaps] = 0
-- reserved
for i = 9, 17 do
self[i] = 0
end
self[18] = MAKEFOURCC("_LUA")
self[19] = MAKEFOURCC("_DDS")
-- pixel format
self[_psize] = 32
self[_pflags] = 0
self[_pfourcc] = 0
self[_pbpp] = 0
self[_prmask] = 0
self[_pgmask] = 0
self[_pbmask] = 0
self[_pamask] = 0
-- caps
self[_caps1] = DDSCAPS_TEXTURE
self[_caps2] = 0
self[_caps3] = 0
self[_caps4] = 0
self[_notused] = 0
-- d3d10
self[_dxgiFmt] = DXGI_FORMAT_UNKNOWN
self[_resDim] = D3D10_RESOURCE_DIMENSION_UNKNOWN
self[_miscFlag] = 0
self[_arraySize]= 0
self[_reserved] = 0
end
function DDSHeader:set_width(num)
self[_flags] = self[_flags] | DDSD_WIDTH
self[_width] = num
end
function DDSHeader:set_height(num)
self[_flags] = self[_flags] | DDSD_HEIGHT
self[_height] = num
end
function DDSHeader:set_depth(num)
self[_flags] = self[_flags] | DDSD_DEPTH
self[_depth] = num
end
function DDSHeader:set_mipmaps(num)
if num == 0 or num == 1 then
self[_flags] = self[_flags] & ~DDSD_MIPMAPCOUNT
if self[_caps2] == 0 then
self[_caps1] = DDSCAPS_TEXTURE
else
self[_caps1] = DDSCAPS_TEXTURE | DDSCAPS_COMPLEX
end
else
self[_flags] = self[_flags] | DDSD_MIPMAPCOUNT
self[_mipmaps] = num
self[_caps1] = self[_caps1] | DDSCAPS_COMPLEX | DDSCAPS_MIPMAP
end
end
function DDSHeader:set_texture_2d()
self[_resDim] = D3D10_RESOURCE_DIMENSION_TEXTURE2D
end
function DDSHeader:set_texture_3d()
self[_caps2] = DDSCAPS2_VOLUME
self[_resDim] = D3D10_RESOURCE_DIMENSION_TEXTURE3D
end
function DDSHeader:set_texture_cube()
self[_caps1] = self[_caps1]| DDSCAPS_COMPLEX
self[_caps2] = DDSCAPS2_CUBEMAP | DDSCAPS2_CUBEMAP_ALL_FACES
self[_resDim] = D3D10_RESOURCE_DIMENSION_TEXTURE2D
self[_arraySize] = 6
end
function DDSHeader:set_linear(size)
self[_flags] = self[_flags] & ~DDSD_PITCH
self[_flags] = self[_flags] | DDSD_LINEARSIZE
self[_pitch] = size
end
function DDSHeader:set_pitch(pitch)
self[_flags] = self[_flags] & ~DDSD_LINEARSIZE
self[_flags] = self[_flags] | DDSD_PITCH
self[_pitch] = pitch
end
function DDSHeader:set_fourcc(fourcc)
self[_pflags] = DDPF_FOURCC
self[_pfourcc] = fourcc
if self[_pfourcc] == FOURCC_ATI2 then
self[_pbpp] = FOURCC_A2XY
else
self[_pbpp] = 0
end
self[_prmask] = 0
self[_pgmask] = 0
self[_pbmask] = 0
self[_pamask] = 0
end
function DDSHeader:set_pixel_format(bpp, rmask, gmask, bmask, amask)
rmask = rmask or 0
gmask = gmask or 0
bmask = bmask or 0
amask = amask or 0
assert((rmask & gmask) == 0)
assert((rmask & bmask) == 0)
assert((rmask & amask) == 0)
assert((gmask & bmask) == 0)
assert((gmask & amask) == 0)
assert((bmask & amask) == 0)
self[_pflags] = DDPF_RGB
if amask ~= 0 then
self[_pflags] = self[_pflags] | DDPF_ALPHAPIXELS
end
if bpp == 0 then
local total = rmask | gmask | bmask | amask
while total ~= 0 do
bpp = bpp + 1
total = total >> 1
end
end
assert(bpp > 0 and bpp <= 32)
-- align to 8
if bpp <= 8 then bpp = 8
elseif bpp <= 16 then bpp = 16
elseif bpp <= 24 then bpp = 24
else bpp = 32
end
self[_pfourcc] = 0
self[_pbpp] = bpp
self[_prmask] = rmask
self[_pgmask] = gmask
self[_pbmask] = bmask
self[_pamask] = amask
end
function DDSHeader:set_normal_flag(b)
if b then
self[_pflags] = self[_pflags] | DDPF_NORMAL
else
self[_pflags] = self[_pflags] & ~DDPF_NORMAL
end
end
function DDSHeader:hasDX10Header()
return self[_pfourcc] == FOURCC_DX10 -- This is according to AMD
--return self[_pfourcc] == 0 -- This is according to MS
end
-------------------------------------------------------------------------------
local function computePitch(width, bpp)
local pitch = (bpp + 7) // 8 * width
return (pitch + 3) // 4 * 4
end
local BS = { 8, 8, 16, 16, 16, 8, 16 }
local function blockSize(fmt)
return BS[fmt] or 0
end
local function computeImageSize(width, height, depth, bpp, fmt)
if fmt == Format_RGBA then
return computePitch(width, bpp) * depth * height
else
return blockSize(fmt) * ((width + 3) // 4) * ((height + 3) // 4)
end
end
-------------------------------------------------------------------------------
function DDSHeader:generate(width, height, mips, fmt, bpp, cubemap, depth, normal)
width = width or 256
height = height or 256
mips = mips or 1
fmt = fmt or Format_DXT1
bpp = bpp or 16
cubemap = cubemap or false
depth = depth or 0
normal = normal or false
self:set_width(width)
self:set_height(height)
self:set_mipmaps(mips)
if depth > 0 then
self:set_depth(depth)
self:set_texture_3d()
else
self:set_texture_2d()
end
if cubemap then
self:set_texture_cube()
end
if fmt == Format_RGBA then
self:set_pitch(computePitch(width, bpp))
if bpp == 8 then
self:set_pixel_format(bpp, 0x0f00, 0x00f0, 0x000f, 0xf000)
elseif bpp == 16 then
-- TODO: check this
self:set_pixel_format(bpp, 0x03f000, 0x000fc0, 0x00003f, 0xfc0000)
elseif bpp == 32 then
self:set_pixel_format(bpp, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)
end
else
self:set_linear(computeImageSize(width, height, depth, bpp, fmt))
if fmt == Format_DXT1 or fmt == Format_DXT1a then
self:set_fourcc(FOURCC_DXT1)
if normal then self:set_normal_flag(true) end
elseif fmt == Format_DXT3 then
self:set_fourcc(FOURCC_DXT3)
elseif fmt == Format_DXT5 then
self:set_fourcc(FOURCC_DXT5)
elseif fmt == Format_DXT5n then
self:set_fourcc(FOURCC_DXT5)
if normal then self:set_normal_flag(true) end
elseif fmt == Format_BC4 then
self:set_fourcc(FOURCC_ATI1)
elseif fmt == Format_DXT3 then
self:set_fourcc(FOURCC_ATI2)
if normal then self:set_normal_flag(true) end
end
end
-- TODO: swapBytes()
local header_size = 128 // 4
if self:hasDX10Header() then
header_size = (128 + 20) // 4
end
local data = {}
for i = 1, header_size do
table.insert(data, string.pack("<I", self[i]))
end
return table.concat(data)
end