Blender  V3.3
FlipDXT.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2009 Google Inc. All rights reserved. */
3 
10 #include "IMB_imbuf_types.h"
11 
12 #include <cstring>
13 
14 #include <BlockDXT.h>
15 #include <ColorBlock.h>
16 #include <Common.h>
17 #include <FlipDXT.h>
18 #include <Stream.h>
19 
20 /* A function that flips a DXTC block. */
21 using FlipBlockFunction = void (*)(uint8_t *block);
22 
23 /* Flips a full DXT1 block in the y direction. */
24 static void FlipDXT1BlockFull(uint8_t *block)
25 {
26  /* A DXT1 block layout is:
27  * [0-1] color0.
28  * [2-3] color1.
29  * [4-7] color bitmap, 2 bits per pixel.
30  * So each of the 4-7 bytes represents one line, flipping a block is just
31  * flipping those bytes. */
32  uint8_t tmp = block[4];
33  block[4] = block[7];
34  block[7] = tmp;
35  tmp = block[5];
36  block[5] = block[6];
37  block[6] = tmp;
38 }
39 
40 /* Flips the first 2 lines of a DXT1 block in the y direction. */
41 static void FlipDXT1BlockHalf(uint8_t *block)
42 {
43  /* See layout above. */
44  uint8_t tmp = block[4];
45  block[4] = block[5];
46  block[5] = tmp;
47 }
48 
49 /* Flips a full DXT3 block in the y direction. */
50 static void FlipDXT3BlockFull(uint8_t *block)
51 {
52  /* A DXT3 block layout is:
53  * [0-7] alpha bitmap, 4 bits per pixel.
54  * [8-15] a DXT1 block. */
55 
56  /* We can flip the alpha bits at the byte level (2 bytes per line). */
57  uint8_t tmp = block[0];
58 
59  block[0] = block[6];
60  block[6] = tmp;
61  tmp = block[1];
62  block[1] = block[7];
63  block[7] = tmp;
64  tmp = block[2];
65  block[2] = block[4];
66  block[4] = tmp;
67  tmp = block[3];
68  block[3] = block[5];
69  block[5] = tmp;
70 
71  /* And flip the DXT1 block using the above function. */
72  FlipDXT1BlockFull(block + 8);
73 }
74 
75 /* Flips the first 2 lines of a DXT3 block in the y direction. */
76 static void FlipDXT3BlockHalf(uint8_t *block)
77 {
78  /* See layout above. */
79  uint8_t tmp = block[0];
80 
81  block[0] = block[2];
82  block[2] = tmp;
83  tmp = block[1];
84  block[1] = block[3];
85  block[3] = tmp;
86  FlipDXT1BlockHalf(block + 8);
87 }
88 
89 /* Flips a full DXT5 block in the y direction. */
90 static void FlipDXT5BlockFull(uint8_t *block)
91 {
92  /* A DXT5 block layout is:
93  * [0] alpha0.
94  * [1] alpha1.
95  * [2-7] alpha bitmap, 3 bits per pixel.
96  * [8-15] a DXT1 block. */
97 
98  /* The alpha bitmap doesn't easily map lines to bytes, so we have to
99  * interpret it correctly. Extracted from
100  * http://www.opengl.org/registry/specs/EXT/texture_compression_s3tc.txt :
101  *
102  * The 6 "bits" bytes of the block are decoded into one 48-bit integer:
103  *
104  * bits = bits_0 + 256 * (bits_1 + 256 * (bits_2 + 256 * (bits_3 +
105  * 256 * (bits_4 + 256 * bits_5))))
106  *
107  * bits is a 48-bit unsigned integer, from which a three-bit control code
108  * is extracted for a texel at location (x,y) in the block using:
109  *
110  * code(x,y) = bits[3*(4*y+x)+1..3*(4*y+x)+0]
111  *
112  * where bit 47 is the most significant and bit 0 is the least
113  * significant bit. */
114  unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
115  unsigned int line_2_3 = block[5] + 256 * (block[6] + 256 * block[7]);
116  /* swap lines 0 and 1 in line_0_1. */
117  unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
118  /* swap lines 2 and 3 in line_2_3. */
119  unsigned int line_3_2 = ((line_2_3 & 0x000fff) << 12) | ((line_2_3 & 0xfff000) >> 12);
120 
121  block[2] = line_3_2 & 0xff;
122  block[3] = (line_3_2 & 0xff00) >> 8;
123  block[4] = (line_3_2 & 0xff0000) >> 16;
124  block[5] = line_1_0 & 0xff;
125  block[6] = (line_1_0 & 0xff00) >> 8;
126  block[7] = (line_1_0 & 0xff0000) >> 16;
127 
128  /* And flip the DXT1 block using the above function. */
129  FlipDXT1BlockFull(block + 8);
130 }
131 
132 /* Flips the first 2 lines of a DXT5 block in the y direction. */
133 static void FlipDXT5BlockHalf(uint8_t *block)
134 {
135  /* See layout above. */
136  unsigned int line_0_1 = block[2] + 256 * (block[3] + 256 * block[4]);
137  unsigned int line_1_0 = ((line_0_1 & 0x000fff) << 12) | ((line_0_1 & 0xfff000) >> 12);
138  block[2] = line_1_0 & 0xff;
139  block[3] = (line_1_0 & 0xff00) >> 8;
140  block[4] = (line_1_0 & 0xff0000) >> 16;
141  FlipDXT1BlockHalf(block + 8);
142 }
143 
144 int FlipDXTCImage(unsigned int width,
145  unsigned int height,
146  unsigned int levels,
147  int fourcc,
148  uint8_t *data,
149  int data_size,
150  unsigned int *r_num_valid_levels)
151 {
152  *r_num_valid_levels = 0;
153 
154  /* Must have valid dimensions. */
155  if (width == 0 || height == 0) {
156  return 0;
157  }
158  /* Height must be a power-of-two. */
159  if ((height & (height - 1)) != 0) {
160  return 0;
161  }
162 
163  FlipBlockFunction full_block_function;
164  FlipBlockFunction half_block_function;
165  unsigned int block_bytes = 0;
166 
167  switch (fourcc) {
168  case FOURCC_DXT1:
169  full_block_function = FlipDXT1BlockFull;
170  half_block_function = FlipDXT1BlockHalf;
171  block_bytes = 8;
172  break;
173  case FOURCC_DXT3:
174  full_block_function = FlipDXT3BlockFull;
175  half_block_function = FlipDXT3BlockHalf;
176  block_bytes = 16;
177  break;
178  case FOURCC_DXT5:
179  full_block_function = FlipDXT5BlockFull;
180  half_block_function = FlipDXT5BlockHalf;
181  block_bytes = 16;
182  break;
183  default:
184  return 0;
185  }
186 
187  *r_num_valid_levels = levels;
188 
189  unsigned int mip_width = width;
190  unsigned int mip_height = height;
191 
192  const uint8_t *data_end = data + data_size;
193 
194  for (unsigned int i = 0; i < levels; i++) {
195  unsigned int blocks_per_row = (mip_width + 3) / 4;
196  unsigned int blocks_per_col = (mip_height + 3) / 4;
197  unsigned int blocks = blocks_per_row * blocks_per_col;
198 
199  if (data + block_bytes * blocks > data_end) {
200  /* Stop flipping when running out of data to be modified, avoiding possible buffer overrun
201  * on a malformed files. */
202  *r_num_valid_levels = i;
203  break;
204  }
205 
206  if (mip_height == 1) {
207  /* no flip to do, and we're done. */
208  break;
209  }
210  if (mip_height == 2) {
211  /* flip the first 2 lines in each block. */
212  for (unsigned int i = 0; i < blocks_per_row; i++) {
213  half_block_function(data + i * block_bytes);
214  }
215  }
216  else {
217  /* flip each block. */
218  for (unsigned int i = 0; i < blocks; i++) {
219  full_block_function(data + i * block_bytes);
220  }
221 
222  /* Swap each block line in the first half of the image with the
223  * corresponding one in the second half.
224  * note that this is a no-op if mip_height is 4. */
225  unsigned int row_bytes = block_bytes * blocks_per_row;
226  uint8_t *temp_line = new uint8_t[row_bytes];
227 
228  for (unsigned int y = 0; y < blocks_per_col / 2; y++) {
229  uint8_t *line1 = data + y * row_bytes;
230  uint8_t *line2 = data + (blocks_per_col - y - 1) * row_bytes;
231 
232  memcpy(temp_line, line1, row_bytes);
233  memcpy(line1, line2, row_bytes);
234  memcpy(line2, temp_line, row_bytes);
235  }
236 
237  delete[] temp_line;
238  }
239 
240  /* mip levels are contiguous. */
241  data += block_bytes * blocks;
242  mip_width = MAX(1U, mip_width >> 1);
243  mip_height = MAX(1U, mip_height >> 1);
244  }
245 
246  return 1;
247 }
#define MAX(a, b)
Definition: Common.h:13
static const uint FOURCC_DXT3
static const uint FOURCC_DXT5
static const uint FOURCC_DXT1
static void FlipDXT3BlockFull(uint8_t *block)
Definition: FlipDXT.cpp:50
void(*)(uint8_t *block) FlipBlockFunction
Definition: FlipDXT.cpp:21
static void FlipDXT5BlockHalf(uint8_t *block)
Definition: FlipDXT.cpp:133
static void FlipDXT1BlockFull(uint8_t *block)
Definition: FlipDXT.cpp:24
static void FlipDXT5BlockFull(uint8_t *block)
Definition: FlipDXT.cpp:90
static void FlipDXT1BlockHalf(uint8_t *block)
Definition: FlipDXT.cpp:41
static void FlipDXT3BlockHalf(uint8_t *block)
Definition: FlipDXT.cpp:76
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:144
_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
_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
Contains defines and structs used throughout the imbuf module.
SyclQueue void void size_t num_bytes void
unsigned char uint8_t
Definition: stdint.h:78