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: |