1 /**
2 * libsquish/rg_etc1 bridging interface
3 */
4
5 #include "build.h"
6
7 #if USE_POLYMOST && USE_OPENGL
8
9 #include "polymosttexcompress.h"
10
11 #include "squish.h"
12 #include "rg_etc1.h"
13
14 extern "C" {
15 #include "glbuild.h"
16 extern int gltexcomprquality;
17 }
18
getsquishflags(int format)19 static int getsquishflags(int format)
20 {
21 int flags;
22
23 switch (gltexcomprquality) {
24 case 2: flags = squish::kColourIterativeClusterFit; // slower
25 break;
26 case 1: flags = squish::kColourClusterFit; // slow, but also quite good looking
27 break;
28 default: flags = squish::kColourRangeFit; // fast, but worse quality
29 break;
30 }
31
32 flags |= squish::kSourceBGRA;
33 if (format == PTCOMPRESS_DXT1) {
34 flags |= squish::kDxt1;
35 } else if (format == PTCOMPRESS_DXT5) {
36 flags |= squish::kDxt5;
37 }
38
39 return flags;
40 }
41
compressetc1(uint8_t * bgra,int width,int height,uint8_t * out)42 static void compressetc1(uint8_t *bgra, int width, int height, uint8_t *out)
43 {
44 rg_etc1::etc1_pack_params params;
45 uint8_t block[4][4][4];
46 int x, y, s, t, xyoff, stride;
47
48 static int initonce = 0;
49 if (!initonce) {
50 rg_etc1::pack_etc1_block_init();
51 initonce = 1;
52 }
53
54 switch (gltexcomprquality) {
55 case 2: params.m_quality = rg_etc1::cHighQuality; break;
56 case 1: params.m_quality = rg_etc1::cMediumQuality; break;
57 default: params.m_quality = rg_etc1::cLowQuality; break;
58 }
59
60 stride = width * 4;
61 for (y = 0; y < height; y += 4) {
62 for (x = 0; x < width; x += 4) {
63 xyoff = y * stride + x * 4;
64
65 // Copy the block of pixels to encode, byte swizzling to RGBA order.
66 for (t = 0; t < min(4, height - y); t++) {
67 for (s = 0; s < min(4, width - x); s++) {
68 block[t][s][0] = bgra[xyoff + t * stride + s * 4 + 2];
69 block[t][s][1] = bgra[xyoff + t * stride + s * 4 + 1];
70 block[t][s][2] = bgra[xyoff + t * stride + s * 4 + 0];
71 block[t][s][3] = 255;
72 }
73 // Repeat the final pixel to pad to 4.
74 for (; s < 4; s++) {
75 memcpy(&block[t][s][0], &block[t][s-1][0], 4);
76 }
77 }
78 // Repeat the final row to pad to 4.
79 for (; t < 4; t++) {
80 memcpy(&block[t][0][0], &block[t-1][0][0], 4 * 4);
81 }
82
83 rg_etc1::pack_etc1_block(out, (const uint32_t *)block, params);
84
85 out += 8;
86 }
87 }
88 }
89
ptcompress_getstorage(int width,int height,int format)90 extern "C" int ptcompress_getstorage(int width, int height, int format)
91 {
92 switch (format) {
93 case PTCOMPRESS_DXT1:
94 case PTCOMPRESS_DXT5:
95 return squish::GetStorageRequirements(width, height, getsquishflags(format));
96 case PTCOMPRESS_ETC1:
97 return 8 * ((width + 3) / 4) * ((height + 3) / 4);
98 }
99 return 0;
100 }
101
ptcompress_compress(void * bgra,int width,int height,unsigned char * output,int format)102 extern "C" int ptcompress_compress(void * bgra, int width, int height, unsigned char * output, int format)
103 {
104 switch (format) {
105 case PTCOMPRESS_DXT1:
106 case PTCOMPRESS_DXT5:
107 squish::CompressImage( (squish::u8 const *) bgra, width, height, output, getsquishflags(format));
108 return 0;
109 case PTCOMPRESS_ETC1:
110 compressetc1((uint8_t *)bgra, width, height, output);
111 return 0;
112 }
113 return -1;
114 }
115
116 #endif //USE_OPENGL
117