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