summaryrefslogtreecommitdiff
path: root/convtexture.c
diff options
context:
space:
mode:
Diffstat (limited to 'convtexture.c')
-rw-r--r--convtexture.c130
1 files changed, 127 insertions, 3 deletions
diff --git a/convtexture.c b/convtexture.c
index a321a9d..b3be7dc 100644
--- a/convtexture.c
+++ b/convtexture.c
@@ -23,6 +23,11 @@ typedef struct {
unsigned char indices[4 * 4];
} Block;
+typedef struct {
+ float start, end;
+ unsigned char indices[4 * 4];
+} Block_BC4;
+
const char* format_names[] = {
#define x(n) #n,
texture_format_xmacro()
@@ -36,6 +41,10 @@ unsigned encode_endpoint(const vec3* v) {
((unsigned)(v->b * 31.9999f));
}
+unsigned encode_endpoint_bc4(float v) {
+ return (unsigned)(v * 255.0f);
+}
+
void get_block(Block* block, Colour* pixels, int stride) {
int x, y, i;
vec3 cols[4 * 4];
@@ -125,13 +134,97 @@ void compress_block(const Block* block, FILE* f) {
fwrite(&start, 1, 2, f);
fwrite(&end, 1, 2, f);
for (i = 0; i < 4 * 4; i++) {
- int idx = (4 * 4 - 1) - i;
- idx = i;
- indices |= block->indices[i] << (idx * 2);
+ indices |= block->indices[i] << (i * 2);
}
fwrite(&indices, 1, 4, f);
}
+void get_block_bc4(
+ Block_BC4* block,
+ Colour* pixels,
+ int stride,
+ int channel
+) {
+ int x, y;
+ float palette[8];
+ palette[0] = 0.08f;
+ palette[1] = 0.92f;
+ float biggest = -1.0f;
+ float smallest = 1.0f;
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ uint8_t* pixel = (uint8_t*)&pixels[x + y * stride];
+ float v = (float)pixel[channel] / 255.0f;
+ if (v > biggest) biggest = v;
+ if (v < smallest) smallest = v;
+ if (v > palette[0]) palette[0] = v;
+ if (v < palette[1]) palette[1] = v;
+ }
+ }
+ if (biggest == smallest) {
+ int i, idx = 1;
+ block->end = biggest;
+ if (palette[0] > 0.9f) {
+ idx = 0;
+ block->start = smallest;
+ block->end = 0.0f;
+ } else
+ block->start = 1.0f;
+ assert(block->start > block->end);
+ for (i = 0; i < 16; i++)
+ block->indices[i] = idx;
+ }
+ if (biggest > 0.92f && smallest < 0.08f) {
+ float t = palette[1];
+ palette[1] = palette[0];
+ palette[0] = t;
+ palette[2] = (4.0f * palette[0] + 1.0f * palette[1]) / 5.0f;
+ palette[3] = (3.0f * palette[0] + 2.0f * palette[1]) / 5.0f;
+ palette[4] = (2.0f * palette[0] + 3.0f * palette[1]) / 5.0f;
+ palette[5] = (1.0f * palette[0] + 4.0f * palette[1]) / 5.0f;
+ palette[6] = 0.0f;
+ palette[7] = 1.0f;
+ } else {
+ palette[2] = (6.0f * palette[0] + 1.0f * palette[1]) / 7.0f;
+ palette[3] = (5.0f * palette[0] + 2.0f * palette[1]) / 7.0f;
+ palette[4] = (4.0f * palette[0] + 3.0f * palette[1]) / 7.0f;
+ palette[5] = (3.0f * palette[0] + 4.0f * palette[1]) / 7.0f;
+ palette[6] = (2.0f * palette[0] + 5.0f * palette[1]) / 7.0f;
+ palette[7] = (1.0f * palette[0] + 6.0f * palette[1]) / 7.0f;
+ }
+ block->start = palette[0];
+ block->end = palette[1];
+ for (y = 0; y < 4; y++) {
+ for (x = 0; x < 4; x++) {
+ uint8_t* pixel = (uint8_t*)&pixels[x + y * stride];
+ float v = (float)pixel[channel] / 255.0f;
+ float d = 100.0f;
+ int i;
+ for (i = 0; i < 8; i++) {
+ float d2 = (v - palette[i]);
+ d2 = d2 < 0.0f? -d2: d2;
+ if (d2 < d) {
+ d = d2;
+ block->indices[x + y * 4] = i;
+ }
+ }
+ }
+ }
+}
+
+void compress_block_bc4(const Block_BC4* block, FILE* f) {
+ int i;
+ unsigned start = encode_endpoint_bc4(block->start);
+ unsigned end = encode_endpoint_bc4(block->end);
+ uint64_t indices = 0;
+ fwrite(&start, 1, 1, f);
+ fwrite(&end, 1, 1, f);
+ for (i = 0; i < 4 * 4; i++) {
+ indices |= ((uint64_t)block->indices[i]) << (i * 3);
+ } /* 48 bits of indices */
+ fwrite(&indices, 1, 6, f);
+}
+
void compress_bc1(Colour* pixels, int w, int h, FILE* f) {
int x, y, cw, ch;
Block block;
@@ -145,6 +238,31 @@ void compress_bc1(Colour* pixels, int w, int h, FILE* f) {
}
}
+void compress_bc4(Colour* pixels, int w, int h, FILE* f) {
+ int x, y, cw = w / 4, ch = h / 4;
+ Block_BC4 block;
+ for (y = 0; y < ch; y++) {
+ for (x = 0; x < cw; x++) {
+ get_block_bc4(&block, &pixels[x * 4 + y * 4 * w], w, 0);
+ compress_block_bc4(&block, f);
+ }
+ }
+}
+
+void compress_bc5(Colour* pixels, int w, int h, FILE* f) {
+ int x, y, cw = w / 4, ch = h / 4;
+ Block_BC4 a, b;
+ for (y = 0; y < ch; y++) {
+ for (x = 0; x < cw; x++) {
+ Colour* p = &pixels[x * 4 + y * 4 * w];
+ get_block_bc4(&a, p, w, 0);
+ get_block_bc4(&b, p, w, 1);
+ compress_block_bc4(&a, f);
+ compress_block_bc4(&b, f);
+ }
+ }
+}
+
void convert(Image* image, Texture_Format target, FILE* f) {
fwrite("TXTR", 1, 4, f);
fwrite(&image->w, 1, 4, f);
@@ -154,6 +272,12 @@ void convert(Image* image, Texture_Format target, FILE* f) {
case texture_format_bc1:
compress_bc1(image->pixels, image->w, image->h, f);
break;
+ case texture_format_bc4:
+ compress_bc4(image->pixels, image->w, image->h, f);
+ break;
+ case texture_format_bc5:
+ compress_bc5(image->pixels, image->w, image->h, f);
+ break;
default:
print_err("Unsupported target format.\n");
pbreak(40);