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