summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--convtexture.c130
-rw-r--r--vid_enums.h2
-rw-r--r--video.cpp5
3 files changed, 134 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);
diff --git a/vid_enums.h b/vid_enums.h
index d96f57c..170b864 100644
--- a/vid_enums.h
+++ b/vid_enums.h
@@ -17,6 +17,8 @@
x(rgba16f) \
x(rgba32f) \
x(bc1) \
+ x(bc4) \
+ x(bc5) \
x(d16) \
x(d24s8) \
x(d32)
diff --git a/video.cpp b/video.cpp
index 1dc8f68..abcf47d 100644
--- a/video.cpp
+++ b/video.cpp
@@ -283,6 +283,8 @@ static VkFormat get_vk_format(Texture_Format fmt) {
case texture_format_rgba16f: return VK_FORMAT_R16G16B16A16_SFLOAT;
case texture_format_rgba32f: return VK_FORMAT_R32G32B32A32_SFLOAT;
case texture_format_bc1: return VK_FORMAT_BC1_RGB_UNORM_BLOCK;
+ case texture_format_bc4: return VK_FORMAT_BC4_UNORM_BLOCK;
+ case texture_format_bc5: return VK_FORMAT_BC5_UNORM_BLOCK;
case texture_format_d16: return VK_FORMAT_D16_UNORM;
case texture_format_d24s8: return VK_FORMAT_D24_UNORM_S8_UINT;
case texture_format_d32: return VK_FORMAT_D32_SFLOAT;
@@ -3633,7 +3635,10 @@ size_t Texture_Loader::calc_size(
) {
switch (fmt) {
case texture_format_bc1:
+ case texture_format_bc4:
return (w / 4) * (h / 4) * 8;
+ case texture_format_bc5:
+ return (w / 4) * (h / 4) * 16;
case texture_format_r8i:
return w * h;
default: