diff options
-rw-r--r-- | convtexture.c | 130 | ||||
-rw-r--r-- | vid_enums.h | 2 | ||||
-rw-r--r-- | video.cpp | 5 |
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) @@ -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: |