1//
2// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7#include <ddraw.h>
8#include <d3d9types.h>
9#include <stdio.h>
10#include <fstream>
11#include <vector>
12#include <iostream>
13#include <string>
14#include <algorithm>
15#include <array>
16
17int main(int argc, char **argv)
18{
19    std::string programName(argv[0]);
20    if (argc < 4)
21    {
22        std::cout << "usage:\n";
23        std::cout << programName << "INPUT_FILE OUTPUT_C_ARRAY_NAME OUTPUT_FILE\n";
24        return -1;
25    }
26
27    std::string inputFile(argv[1]);
28    std::string outputName(argv[2]);
29    std::string outputFile(argv[3]);
30    std::ifstream readFile(inputFile, std::ios::binary | std::ios::in);
31
32    readFile.seekg(0, std::ios::end);
33    std::streamoff fileSize = readFile.tellg();
34    readFile.seekg(0, std::ios::beg);
35
36    const std::size_t minSize = sizeof(DDSURFACEDESC2) + sizeof(DWORD);
37    if (fileSize < minSize)
38    {
39        std::cout << inputFile << " is only " << fileSize << " bytes, must be at greater than " << minSize
40                  << " bytes to be a correct DDS image file.\n";
41        return -2;
42    }
43
44    DWORD magicWord;
45    readFile.read(reinterpret_cast<char*>(&magicWord), sizeof(DWORD));
46    if (magicWord != MAKEFOURCC('D','D','S',' '))
47    {
48        std::cout << "Magic word must be " << MAKEFOURCC('D','D','S',' ') << ".\n";
49        return -3;
50    }
51
52    DDSURFACEDESC2 header;
53    readFile.read(reinterpret_cast<char*>(&header), sizeof(DDSURFACEDESC2));
54
55    std::string formatName;
56    std::size_t blockSize = 0;
57    std::size_t blockWidth = 0;
58    std::size_t blockHeight = 0;
59
60    if (header.ddpfPixelFormat.dwFlags & DDPF_RGB)
61    {
62        blockSize = header.ddpfPixelFormat.dwRGBBitCount / 8;
63        blockWidth = 1;
64        blockHeight = 1;
65
66        if (blockSize == 4)
67        {
68            if (header.ddpfPixelFormat.dwRBitMask        == 0x000000FF &&
69                header.ddpfPixelFormat.dwGBitMask        == 0x0000FF00 &&
70                header.ddpfPixelFormat.dwBBitMask        == 0x00FF0000 &&
71                header.ddpfPixelFormat.dwRGBAlphaBitMask == 0xFF000000)
72            {
73                formatName = "RGBA8";
74            }
75            else if (header.ddpfPixelFormat.dwRBitMask       == 0x000000FF &&
76                    header.ddpfPixelFormat.dwGBitMask        == 0x0000FF00 &&
77                    header.ddpfPixelFormat.dwBBitMask        == 0x00FF0000 &&
78                    header.ddpfPixelFormat.dwRGBAlphaBitMask == 0x00000000)
79            {
80                formatName = "RGBX8";
81            }
82            else if (header.ddpfPixelFormat.dwRBitMask       == 0x000003FF &&
83                    header.ddpfPixelFormat.dwGBitMask        == 0x000FFC00 &&
84                    header.ddpfPixelFormat.dwBBitMask        == 0x3FF00000 &&
85                    header.ddpfPixelFormat.dwRGBAlphaBitMask == 0xC0000000)
86            {
87                formatName = "RGB10A2";
88            }
89            else if (header.ddpfPixelFormat.dwRBitMask       == 0x0000FFFF &&
90                    header.ddpfPixelFormat.dwGBitMask        == 0xFFFF0000 &&
91                    header.ddpfPixelFormat.dwBBitMask        == 0x00000000 &&
92                    header.ddpfPixelFormat.dwRGBAlphaBitMask == 0x00000000)
93            {
94                formatName = "RG16";
95            }
96            else if (header.ddpfPixelFormat.dwRBitMask       == 0xFFFFFFFF &&
97                    header.ddpfPixelFormat.dwGBitMask        == 0x00000000 &&
98                    header.ddpfPixelFormat.dwBBitMask        == 0x00000000 &&
99                    header.ddpfPixelFormat.dwRGBAlphaBitMask == 0x00000000)
100            {
101                formatName = "R32";
102            }
103            else
104            {
105                formatName = "UKNOWN";
106            }
107        }
108    }
109    else if (header.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
110    {
111        switch (header.ddpfPixelFormat.dwFourCC)
112        {
113          case MAKEFOURCC('D','X','T','1'):
114            formatName = "DXT1";
115            blockSize = 8;
116            blockWidth = 4;
117            blockHeight = 4;
118            break;
119
120          case MAKEFOURCC('D','X','T','3'):
121            formatName = "DXT3";
122            blockSize = 16;
123            blockWidth = 4;
124            blockHeight = 4;
125            break;
126
127          case MAKEFOURCC('D','X','T','5'):
128            formatName = "DXT5";
129            blockSize = 16;
130            blockWidth = 4;
131            blockHeight = 4;
132            break;
133
134          case D3DFMT_R32F:
135            formatName = "R32F";
136            blockSize = 4;
137            blockWidth = 1;
138            blockHeight = 1;
139
140          case D3DFMT_G32R32F:
141            formatName = "RG32F";
142            blockSize = 8;
143            blockWidth = 1;
144            blockHeight = 1;
145
146          case D3DFMT_A32B32G32R32F:
147            formatName = "RGBA32F";
148            blockSize = 16;
149            blockWidth = 1;
150            blockHeight = 1;
151
152          case D3DFMT_R16F:
153            formatName = "R16F";
154            blockSize = 2;
155            blockWidth = 1;
156            blockHeight = 1;
157
158          case D3DFMT_G16R16F:
159            formatName = "RG16F";
160            blockSize = 4;
161            blockWidth = 1;
162            blockHeight = 1;
163
164          case D3DFMT_A16B16G16R16F:
165            formatName = "RGBA16F";
166            blockSize = 8;
167            blockWidth = 1;
168            blockHeight = 1;
169
170          default:
171            std::cout << "Unsupported FourCC format.\n";
172            return -5;
173        }
174    }
175    else
176    {
177        std::cout << "Unsupported DDS format.\n";
178        return -6;
179    }
180
181    std::size_t height = header.dwHeight;
182    std::size_t width = header.dwWidth;
183    std::size_t levels = std::max<size_t>(1, header.dwMipMapCount);
184
185    std::ofstream oss(outputFile);
186    oss << "// Automatically generated header from " << inputFile << ", a " << width << "x" << height;
187    if (levels > 1)
188    {
189        oss << " (" << levels << " mip levels)";
190    }
191    oss << "\n// " << formatName << " texture using " << programName << ".\n";
192
193    oss << "static const size_t " << outputName << "_width = " << width << ";\n";
194    oss << "static const size_t " << outputName << "_height = " << height << ";\n";
195    oss << "static const size_t " << outputName << "_levels = " << levels << ";\n";
196    oss << "\n";
197
198    for (std::size_t i = 0; i < levels; ++i)
199    {
200        std::size_t widthAtLevel = std::max<size_t>(width >> i, 1);
201        std::size_t heightAtLevel = std::max<size_t>(height >> i, 1);
202        std::size_t sizeAtLevel = static_cast<std::size_t>(std::ceil(widthAtLevel / static_cast<float>(blockWidth)) *
203                                                           std::ceil(heightAtLevel / static_cast<float>(blockHeight))) *
204                                  blockSize;
205
206        std::vector<unsigned char> data(sizeAtLevel);
207        readFile.read(reinterpret_cast<char*>(data.data()), sizeAtLevel);
208
209        oss << "static const size_t " << outputName << "_" << i << "_width = " << widthAtLevel << ";\n";
210        oss << "static const size_t " << outputName << "_" << i << "_height = " << heightAtLevel << ";\n";
211        oss << "static const size_t " << outputName << "_" << i << "_size = " << sizeAtLevel << ";\n";
212        oss << "static const unsigned char " << outputName << "_" << i << "_data[" << sizeAtLevel << "] =\n";
213        oss << "{";
214        for (std::size_t j = 0; j < sizeAtLevel; j++)
215        {
216            if (j % 16 == 0)
217            {
218                oss << "\n    ";
219            }
220
221            char buffer[32];
222            sprintf_s(buffer, "0x%02X,", data[j]);
223            oss << std::string(buffer);
224        }
225        oss << "\n";
226        oss << "};\n";
227
228        if (i + 1 < levels)
229        {
230            oss << "\n";
231        }
232    }
233
234    oss.close();
235    readFile.close();
236
237    return 0;
238}
239