Browse Source

texturec: Added BC1/2/3 and ETC1 compression.

Branimir Karadžić 10 năm trước cách đây
mục cha
commit
35340d121f
4 tập tin đã thay đổi với 119 bổ sung120 xóa
  1. 4 4
      3rdparty/etc1/etc1.cpp
  2. 36 0
      src/image.cpp
  3. 7 4
      src/image.h
  4. 72 112
      tools/texturec/texturec.cpp

+ 4 - 4
3rdparty/etc1/etc1.cpp

@@ -519,7 +519,7 @@ etc1_uint32 etc1_get_encoded_data_size(etc1_uint32 width, etc1_uint32 height) {
 
 int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 height,
         etc1_uint32 pixelSize, etc1_uint32 stride, etc1_byte* pOut) {
-    if (pixelSize < 2 || pixelSize > 3) {
+    if (pixelSize < 2 || pixelSize > 4) {
         return -1;
     }
     static const unsigned short kYMask[] = { 0x0, 0xf, 0xff, 0xfff, 0xffff };
@@ -546,7 +546,7 @@ int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 heigh
             for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
                 etc1_byte* q = block + (cy * 4) * 3;
                 const etc1_byte* p = pIn + pixelSize * x + stride * (y + cy);
-                if (pixelSize == 3) {
+                if (pixelSize >= 3) {
                     memcpy(q, p, xEnd * 3);
                 } else {
                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {
@@ -576,7 +576,7 @@ int etc1_encode_image(const etc1_byte* pIn, etc1_uint32 width, etc1_uint32 heigh
 int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
         etc1_uint32 width, etc1_uint32 height,
         etc1_uint32 pixelSize, etc1_uint32 stride) {
-    if (pixelSize < 2 || pixelSize > 3) {
+    if (pixelSize < 2 || pixelSize > 4) {
         return -1;
     }
     etc1_byte block[ETC1_DECODED_BLOCK_SIZE];
@@ -599,7 +599,7 @@ int etc1_decode_image(const etc1_byte* pIn, etc1_byte* pOut,
             for (etc1_uint32 cy = 0; cy < yEnd; cy++) {
                 const etc1_byte* q = block + (cy * 4) * 3;
                 etc1_byte* p = pOut + pixelSize * x + stride * (y + cy);
-                if (pixelSize == 3) {
+                if (pixelSize >= 3) {
                     memcpy(p, q, xEnd * 3);
                 } else {
                     for (etc1_uint32 cx = 0; cx < xEnd; cx++) {

+ 36 - 0
src/image.cpp

@@ -213,6 +213,42 @@ namespace bgfx
 		return s_textureFormatName[_format];
 	}
 
+	uint32_t imageGetSize(TextureFormat::Enum _format, uint16_t _width, uint16_t _height, uint16_t _depth, bool _cubeMap, uint8_t _numMips)
+	{
+		const ImageBlockInfo& blockInfo = getBlockInfo(_format);
+		const uint8_t  bpp         = blockInfo.bitsPerPixel;
+		const uint16_t blockWidth  = blockInfo.blockWidth;
+		const uint16_t blockHeight = blockInfo.blockHeight;
+		const uint16_t minBlockX   = blockInfo.minBlockX;
+		const uint16_t minBlockY   = blockInfo.minBlockY;
+
+		_width   = bx::uint16_max(blockWidth  * minBlockX, ( (_width  + blockWidth  - 1) / blockWidth)*blockWidth);
+		_height  = bx::uint16_max(blockHeight * minBlockY, ( (_height + blockHeight - 1) / blockHeight)*blockHeight);
+		_depth   = bx::uint16_max(1, _depth);
+		_numMips = uint8_t(bx::uint16_max(1, _numMips) );
+
+		uint32_t width  = _width;
+		uint32_t height = _height;
+		uint32_t depth  = _depth;
+		uint32_t sides  = _cubeMap ? 6 : 1;
+		uint32_t size   = 0;
+
+		for (uint32_t lod = 0; lod < _numMips; ++lod)
+		{
+			width  = bx::uint32_max(blockWidth  * minBlockX, ( (width  + blockWidth  - 1) / blockWidth )*blockWidth);
+			height = bx::uint32_max(blockHeight * minBlockY, ( (height + blockHeight - 1) / blockHeight)*blockHeight);
+			depth  = bx::uint32_max(1, depth);
+
+			size += width*height*depth*bpp/8 * sides;
+
+			width  >>= 1;
+			height >>= 1;
+			depth  >>= 1;
+		}
+
+		return size;
+	}
+
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst)
 	{
 		uint32_t* dst = (uint32_t*)_dst;

+ 7 - 4
src/image.h

@@ -33,9 +33,9 @@ namespace bgfx
 		uint32_t m_height;
 		uint32_t m_blockSize;
 		uint32_t m_size;
-		uint8_t m_bpp;
-		uint8_t m_format;
-		bool m_hasAlpha;
+		uint8_t  m_bpp;
+		uint8_t  m_format;
+		bool     m_hasAlpha;
 		const uint8_t* m_data;
 	};
 
@@ -84,6 +84,9 @@ namespace bgfx
 	///
 	const char* getName(TextureFormat::Enum _format);
 
+	///
+	uint32_t imageGetSize(TextureFormat::Enum _format, uint16_t _width, uint16_t _height, uint16_t _depth = 0, bool _cubeMap = false, uint8_t _numMips = 0);
+
 	///
 	void imageSolid(uint32_t _width, uint32_t _height, uint32_t _solid, void* _dst);
 
@@ -124,7 +127,7 @@ namespace bgfx
 	void imageDecodeToRgba8(uint8_t* _dst, const uint8_t* _src, uint32_t _width, uint32_t _height, uint32_t _pitch, uint8_t _type);
 
 	///
-	bool imageGetRawData(const ImageContainer& _dds, uint8_t _side, uint8_t _index, const void* _data, uint32_t _size, ImageMip& _mip);
+	bool imageGetRawData(const ImageContainer& _imageContainer, uint8_t _side, uint8_t _index, const void* _data, uint32_t _size, ImageMip& _mip);
 
 } // namespace bgfx
 

+ 72 - 112
tools/texturec/texturec.cpp

@@ -9,7 +9,6 @@
 
 // Just hacking DDS loading code in here.
 #include "bgfx_p.h"
-using namespace bgfx;
 
 #include "image.h"
 #include <libsquish/squish.h>
@@ -58,6 +57,8 @@ void help(const char* _error = NULL)
 
 int main(int _argc, const char* _argv[])
 {
+	using namespace bgfx;
+
 	bx::CommandLine cmdLine(_argc, _argv);
 
 	if (cmdLine.hasArg('h', "help") )
@@ -87,6 +88,33 @@ int main(int _argc, const char* _argv[])
 		return EXIT_FAILURE;
 	}
 
+	const bool  mips = cmdLine.hasArg('m', "mips");
+	const char* type = cmdLine.findOption('t');
+	TextureFormat::Enum format = TextureFormat::BGRA8;
+
+	if (NULL != type)
+	{
+		if (0 == bx::stricmp(type, "bc1")
+		||  0 == bx::stricmp(type, "dxt1") )
+		{
+			format = TextureFormat::BC1;
+		}
+		else if (0 == bx::stricmp(type, "bc2")
+		||       0 == bx::stricmp(type, "dxt3") )
+		{
+			format = TextureFormat::BC2;
+		}
+		else if (0 == bx::stricmp(type, "bc3")
+		||       0 == bx::stricmp(type, "dxt5") )
+		{
+			format = TextureFormat::BC3;
+		}
+		else if (0 == bx::stricmp(type, "etc1") )
+		{
+			format = TextureFormat::ETC1;
+		}
+	}
+
 	uint32_t size = (uint32_t)bx::getSize(&reader);
 	const Memory* mem = alloc(size);
 	bx::read(&reader, mem->data, mem->size);
@@ -94,133 +122,65 @@ int main(int _argc, const char* _argv[])
 
 	ImageContainer imageContainer;
 
-	if (imageParse(imageContainer, mem->data, mem->size) )
+	bool loaded = imageParse(imageContainer, mem->data, mem->size);
+	if (!loaded)
 	{
-		bx::CrtFileWriter writer;
-		if (0 == bx::open(&writer, outputFileName) )
-		{
-			if (NULL != bx::stristr(outputFileName, ".ktx") )
-			{
-				imageWriteKtx(&writer, imageContainer, mem->data, mem->size);
-			}
-
-			bx::close(&writer);
-		}
 	}
 
-#if 0
-	if (imageParse(imageContainer, mem->data, mem->size) )
+	BX_UNUSED(mips);
+	if (loaded)
 	{
-		bool decompress = cmdLine.hasArg('d');
+		bx::CrtAllocator allocator;
+		uint8_t* output = NULL;
 
-		if (decompress
-		||  0 == imageContainer.m_format)
+		ImageMip mip;
+		if (imageGetRawData(imageContainer, 0, 0, mem->data, mem->size, mip) )
 		{
-			for (uint8_t side = 0, numSides = imageContainer.m_cubeMap ? 6 : 1; side < numSides; ++side)
-			{
-				uint32_t width  = imageContainer.m_width;
-				uint32_t height = imageContainer.m_height;
+			uint8_t* rgba = (uint8_t*)BX_ALLOC(&allocator, imageGetSize(TextureFormat::RGBA8, mip.m_width, mip.m_height) );
 
-				for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
-				{
-					width  = bx::uint32_max(1, width);
-					height = bx::uint32_max(1, height);
-
-					ImageMip mip;
-					if (imageGetRawData(imageContainer, side, lod, mem->data, mem->size, mip) )
-					{
-						uint32_t dstpitch = width*4;
-						uint8_t* bits = (uint8_t*)malloc(dstpitch*height);
-
-						if (width  != mip.m_width
-						||  height != mip.m_height)
-						{
-							uint8_t* temp = (uint8_t*)realloc(NULL, mip.m_width*mip.m_height*4);
-							imageDecodeToBgra8(temp, mip.m_data, mip.m_width, mip.m_height, mip.m_width*4, mip.m_format);
-							uint32_t srcpitch = mip.m_width*4;
-
-							for (uint32_t yy = 0; yy < height; ++yy)
-							{
-								uint8_t* src = &temp[yy*srcpitch];
-								uint8_t* dst = &bits[yy*dstpitch];
-
-								for (uint32_t xx = 0; xx < width; ++xx)
-								{
-									memcpy(dst, src, 4);
-									dst += 4;
-									src += 4;
-								}
-							}
-
-							free(temp);
-						}
-						else
-						{
-							imageDecodeToBgra8(bits
-								, mip.m_data
-								, mip.m_width
-								, mip.m_height
-								, mip.m_width*4
-								, mip.m_format
-								);
-						}
-
-						char filePath[256];
-						bx::snprintf(filePath, sizeof(filePath), "mip%d_%d.ktx", side, lod);
-
-						bx::CrtFileWriter writer;
-						if (0 == bx::open(&writer, filePath) )
-						{
-							if (NULL != bx::stristr(filePath, ".ktx") )
-							{
-								imageWriteKtx(&writer
-									, TextureFormat::BGRA8
-									, false
-									, width
-									, height
-									, 0
-									, 1
-									, bits
-									);
-							}
-							else
-							{
-								imageWriteTga(&writer, width, height, dstpitch, bits, false, false);
-							}
-
-							bx::close(&writer);
-						}
-
-						free(bits);
-					}
-
-					width >>= 1;
-					height >>= 1;
-				}
+			imageDecodeToRgba8(rgba, mip.m_data, mip.m_width, mip.m_height, mip.m_width*mip.m_bpp/8, mip.m_format);
+
+			output = (uint8_t*)BX_ALLOC(&allocator, imageGetSize(format, mip.m_width, mip.m_height) );
+
+			switch (format)
+			{
+			case TextureFormat::BC1:
+			case TextureFormat::BC2:
+			case TextureFormat::BC3:
+				squish::CompressImage(rgba, mip.m_width, mip.m_height, output
+					, format == TextureFormat::BC1 ? squish::kDxt1
+					: format == TextureFormat::BC2 ? squish::kDxt3
+					:                                squish::kDxt5
+					);
+				break;
+
+			case TextureFormat::ETC1:
+				etc1_encode_image(rgba, mip.m_width, mip.m_height, 4, mip.m_width*4, output);
+				break;
+
+			default:
+				break;
 			}
+
+			BX_FREE(&allocator, rgba);
 		}
-		else
+
+		if (NULL != output)
 		{
-			for (uint32_t lod = 0, num = imageContainer.m_numMips; lod < num; ++lod)
+			bx::CrtFileWriter writer;
+			if (0 == bx::open(&writer, outputFileName) )
 			{
-				ImageMip mip;
-				if (imageGetRawData(imageContainer, 0, lod, mem->data, mem->size, mip) )
+				if (NULL != bx::stristr(outputFileName, ".ktx") )
 				{
-					char filePath[256];
-					bx::snprintf(filePath, sizeof(filePath), "mip%d.bin", lod);
-
-					bx::CrtFileWriter writer;
-					if (0 == bx::open(&writer, filePath) )
-					{
-						printf("mip%d, size %d\n", lod, mip.m_size);
-						bx::write(&writer, mip.m_data, mip.m_size);
-						bx::close(&writer);
-					}
+					imageWriteKtx(&writer, imageContainer, mem->data, mem->size);
 				}
+
+				bx::close(&writer);
 			}
+
+			BX_FREE(&allocator, output);
 		}
 	}
-#endif // 0
 
 	release(mem);