4f63d17dc902599a335ec6bec382dcc78d2acb93
[blender-staging.git] / source / blender / imbuf / intern / dds / FlipDXT.cpp
1 /*
2  * Copyright 2009, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 // This file comes from the chromium project, adapted to Blender to add DDS
33 // flipping to OpenGL convention for Blender
34
35 #include "IMB_imbuf_types.h"
36
37 #include <string.h>
38
39 #include <Common.h>
40 #include <Stream.h>
41 #include <ColorBlock.h>
42 #include <BlockDXT.h>
43 #include <FlipDXT.h>
44
45 // A function that flips a DXTC block.
46 typedef void (*FlipBlockFunction)(uint8_t *block);
47
48 // Flips a full DXT1 block in the y direction.
49 static void FlipDXT1BlockFull(uint8_t *block)
50 {
51         // A DXT1 block layout is:
52         // [0-1] color0.
53         // [2-3] color1.
54         // [4-7] color bitmap, 2 bits per pixel.
55         // So each of the 4-7 bytes represents one line, flipping a block is just
56         // flipping those bytes.
57         uint8_t tmp = block[4];
58         block[4] = block[7];
59         block[7] = tmp;
60         tmp = block[5];
61         block[5] = block[6];
62         block[6] = tmp;
63 }
64
65 // Flips the first 2 lines of a DXT1 block in the y direction.
66 static void FlipDXT1BlockHalf(uint8_t *block)
67 {
68         // See layout above.
69         uint8_t tmp = block[4];
70         block[4] = block[5];
71         block[5] = tmp;
72 }
73
74 // Flips a full DXT3 block in the y direction.
75 static void FlipDXT3BlockFull(uint8_t *block)
76 {
77         // A DXT3 block layout is:
78         // [0-7]        alpha bitmap, 4 bits per pixel.
79         // [8-15] a DXT1 block.
80
81         // We can flip the alpha bits at the byte level (2 bytes per line).
82         uint8_t tmp = block[0];
83
84         block[0] = block[6];
85         block[6] = tmp;
86         tmp = block[1];
87         block[1] = block[7];
88         block[7] = tmp;
89         tmp = block[2];
90         block[2] = block[4];
91         block[4] = tmp;
92         tmp = block[3];
93         block[3] = block[5];
94         block[5] = tmp;
95
96         // And flip the DXT1 block using the above function.
97         FlipDXT1BlockFull(block + 8);
98 }
99
100 // Flips the first 2 lines of a DXT3 block in the y direction.
101 static void FlipDXT3BlockHalf(uint8_t *block)
102 {
103         // See layout above.
104         uint8_t tmp = block[0];
105
106         block[0] = block[2];
107         block[2] = tmp;
108         tmp = block[1];
109         block[1] = block[3];
110         block[3] = tmp;
111         FlipDXT1BlockHalf(block + 8);
112 }
113
114 // Flips a full DXT5 block in the y direction.
115 static void FlipDXT5BlockFull(uint8_t *block)
116 {
117         // A DXT5 block layout is:
118         // [0]          alpha0.
119         // [1]          alpha1.
120         // [2-7]        alpha bitmap, 3 bits per pixel.
121         // [8-15] a DXT1 block.
122
123         // The alpha bitmap doesn't easily map lines to bytes, so we have to
124         // interpret it correctly.      Extracted from
125         // http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
126         //
127         //       The 6 "bits" bytes of the block are decoded into one 48-bit integer:
128         //
129         //               bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
130         //                                                                       256 * (bits_4 + 256 * bits_5))))
131         //
132         //       bits is a 48-bit unsigned integer, from which a three-bit control code
133         //       is extracted for a texel at location (x,y) in the block using:
134         //
135         //                       code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
136         //
137         //       where bit 47 is the most significant and bit 0 is the least
138         //       significant bit.
139         unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
140         unsigned int line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]);
141         // swap lines 0 and 1 in line_0_1.
142         unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
143                                 ((line_0_1 & 0xfff000) >> 12);
144         // swap lines 2 and 3 in line_2_3.
145         unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) |
146                                 ((line_2_3 & 0xfff000) >> 12);
147
148         block[2] = line_3_2 & 0xff;
149         block[3] = (line_3_2 & 0xff00) >> 8;
150         block[4] = (line_3_2 & 0xff0000) >> 16;
151         block[5] = line_1_0 & 0xff;
152         block[6] = (line_1_0 & 0xff00) >> 8;
153         block[7] = (line_1_0 & 0xff0000) >> 16;
154
155         // And flip the DXT1 block using the above function.
156         FlipDXT1BlockFull(block + 8);
157 }
158
159 // Flips the first 2 lines of a DXT5 block in the y direction.
160 static void FlipDXT5BlockHalf(uint8_t *block)
161 {
162         // See layout above.
163         unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
164         unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) |
165                                 ((line_0_1 & 0xfff000) >> 12);
166         block[2] = line_1_0 & 0xff;
167         block[3] = (line_1_0 & 0xff00) >> 8;
168         block[4] = (line_1_0 & 0xff0000) >> 16;
169         FlipDXT1BlockHalf(block + 8);
170 }
171
172 // Flips a DXTC image, by flipping and swapping DXTC blocks as appropriate.
173 int FlipDXTCImage(unsigned int width, unsigned int height, unsigned int levels, int fourcc, uint8_t *data)
174 {
175         // must have valid dimensions
176         if (width == 0 || height == 0)
177                 return 0;
178         // height must be a power-of-two
179         if ((height & (height - 1)) != 0)
180                 return 0;
181
182         FlipBlockFunction full_block_function;
183         FlipBlockFunction half_block_function;
184         unsigned int block_bytes = 0;
185
186         switch (fourcc) {
187                 case FOURCC_DXT1:
188                         full_block_function = FlipDXT1BlockFull;
189                         half_block_function = FlipDXT1BlockHalf;
190                         block_bytes = 8;
191                         break;
192                 case FOURCC_DXT3:
193                         full_block_function = FlipDXT3BlockFull;
194                         half_block_function = FlipDXT3BlockHalf;
195                         block_bytes = 16;
196                         break;
197                 case FOURCC_DXT5:
198                         full_block_function = FlipDXT5BlockFull;
199                         half_block_function = FlipDXT5BlockHalf;
200                         block_bytes = 16;
201                         break;
202                 default:
203                         return 0;
204         }
205
206         unsigned int mip_width = width;
207         unsigned int mip_height = height;
208
209         for (unsigned int i = 0; i < levels; ++i) {
210                 unsigned int blocks_per_row = (mip_width + 3) / 4;
211                 unsigned int blocks_per_col = (mip_height + 3) / 4;
212                 unsigned int blocks = blocks_per_row * blocks_per_col;
213
214                 if (mip_height == 1) {
215                         // no flip to do, and we're done.
216                         break;
217                 }
218                 else if (mip_height == 2) {
219                         // flip the first 2 lines in each block.
220                         for (unsigned int i = 0; i < blocks_per_row; ++i) {
221                                 half_block_function(data + i * block_bytes);
222                         }
223                 }
224                 else {
225                         // flip each block.
226                         for (unsigned int i = 0; i < blocks; ++i)
227                                 full_block_function(data + i * block_bytes);
228
229                         // swap each block line in the first half of the image with the
230                         // corresponding one in the second half.
231                         // note that this is a no-op if mip_height is 4.
232                         unsigned int row_bytes = block_bytes * blocks_per_row;
233                         uint8_t *temp_line = new uint8_t[row_bytes];
234
235                         for (unsigned int y = 0; y < blocks_per_col / 2; ++y) {
236                                 uint8_t *line1 = data + y * row_bytes;
237                                 uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
238
239                                 memcpy(temp_line, line1, row_bytes);
240                                 memcpy(line1, line2, row_bytes);
241                                 memcpy(line2, temp_line, row_bytes);
242                         }
243
244                         delete[] temp_line;
245                 }
246
247                 // mip levels are contiguous.
248                 data += block_bytes * blocks;
249                 mip_width = max(1U, mip_width >> 1);
250                 mip_height = max(1U, mip_height >> 1);
251         }
252
253         return 1;
254 }
255