Branimir Karadžić 7 роки тому
батько
коміт
c3a55957f2
4 змінених файлів з 248 додано та 28 видалено
  1. 10 0
      include/bimg/bimg.h
  2. 131 1
      src/image.cpp
  3. 106 26
      src/image_cubemap_filter.cpp
  4. 1 1
      tools/texturec/texturec.cpp

+ 10 - 0
include/bimg/bimg.h

@@ -334,6 +334,16 @@ namespace bimg
 		, const void* _src
 		);
 
+	///
+	void imageRgba32fDownsample2x2(
+		  void* _dst
+		, uint32_t _width
+		, uint32_t _height
+		, uint32_t _depth
+		, uint32_t _srcPitch
+		, const void* _src
+		);
+
 	///
 	void imageRgba32fDownsample2x2NormalMap(
 		  void* _dst

+ 131 - 1
src/image.cpp

@@ -709,6 +709,136 @@ namespace bimg
 		imageRgba32fLinearDownsample2x2Ref(_dst, _width, _height, _depth, _srcPitch, _src);
 	}
 
+	void imageRgba32fDownsample2x2Ref(void* _dst, uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _srcPitch, const void* _src)
+	{
+		const uint32_t dstWidth  = _width/2;
+		const uint32_t dstHeight = _height/2;
+		const uint32_t dstDepth  = _depth/2;
+
+		if (0 == dstWidth
+		||  0 == dstHeight)
+		{
+			return;
+		}
+
+		const uint8_t* src = (const uint8_t*)_src;
+		uint8_t* dst = (uint8_t*)_dst;
+
+		if (0 == dstDepth)
+		{
+			for (uint32_t yy = 0, ystep = _srcPitch*2; yy < dstHeight; ++yy, src += ystep)
+			{
+				const float* rgba0 = (const float*)&src[0];
+				const float* rgba1 = (const float*)&src[_srcPitch];
+				for (uint32_t xx = 0; xx < dstWidth; ++xx, rgba0 += 8, rgba1 += 8, dst += 16)
+				{
+					float xyz[4];
+
+					xyz[0]  = bx::toLinear(rgba0[0]);
+					xyz[1]  = bx::toLinear(rgba0[1]);
+					xyz[2]  = bx::toLinear(rgba0[2]);
+					xyz[3]  =              rgba0[3];
+
+					xyz[0] += bx::toLinear(rgba0[4]);
+					xyz[1] += bx::toLinear(rgba0[5]);
+					xyz[2] += bx::toLinear(rgba0[6]);
+					xyz[3] +=              rgba0[7];
+
+					xyz[0] += bx::toLinear(rgba1[0]);
+					xyz[1] += bx::toLinear(rgba1[1]);
+					xyz[2] += bx::toLinear(rgba1[2]);
+					xyz[3] +=              rgba1[3];
+
+					xyz[0] += bx::toLinear(rgba1[4]);
+					xyz[1] += bx::toLinear(rgba1[5]);
+					xyz[2] += bx::toLinear(rgba1[6]);
+					xyz[3] +=              rgba1[7];
+
+					xyz[0] = bx::toGamma(xyz[0]/4.0f);
+					xyz[1] = bx::toGamma(xyz[1]/4.0f);
+					xyz[2] = bx::toGamma(xyz[2]/4.0f);
+					xyz[3] =             xyz[3]/4.0f;
+
+					bx::packRgba32F(dst, xyz);
+				}
+			}
+		}
+		else
+		{
+			const uint32_t slicePitch = _srcPitch*_height;
+
+			for (uint32_t zz = 0; zz < dstDepth; ++zz, src += slicePitch)
+			{
+				for (uint32_t yy = 0, ystep = _srcPitch*2; yy < dstHeight; ++yy, src += ystep)
+				{
+					const float* rgba0 = (const float*)&src[0];
+					const float* rgba1 = (const float*)&src[_srcPitch];
+					const float* rgba2 = (const float*)&src[slicePitch];
+					const float* rgba3 = (const float*)&src[slicePitch+_srcPitch];
+					for (uint32_t xx = 0
+						; xx < dstWidth
+						; ++xx, rgba0 += 8, rgba1 += 8, rgba2 += 8, rgba3 += 8, dst += 16
+						)
+					{
+						float xyz[4];
+
+						xyz[0]  = bx::toLinear(rgba0[0]);
+						xyz[1]  = bx::toLinear(rgba0[1]);
+						xyz[2]  = bx::toLinear(rgba0[2]);
+						xyz[3]  =              rgba0[3];
+
+						xyz[0] += bx::toLinear(rgba0[4]);
+						xyz[1] += bx::toLinear(rgba0[5]);
+						xyz[2] += bx::toLinear(rgba0[6]);
+						xyz[3] +=              rgba0[7];
+
+						xyz[0] += bx::toLinear(rgba1[0]);
+						xyz[1] += bx::toLinear(rgba1[1]);
+						xyz[2] += bx::toLinear(rgba1[2]);
+						xyz[3] +=              rgba1[3];
+
+						xyz[0] += bx::toLinear(rgba1[4]);
+						xyz[1] += bx::toLinear(rgba1[5]);
+						xyz[2] += bx::toLinear(rgba1[6]);
+						xyz[3] +=              rgba1[7];
+
+						xyz[0] += bx::toLinear(rgba2[0]);
+						xyz[1] += bx::toLinear(rgba2[1]);
+						xyz[2] += bx::toLinear(rgba2[2]);
+						xyz[3] +=              rgba2[3];
+
+						xyz[0] += bx::toLinear(rgba2[4]);
+						xyz[1] += bx::toLinear(rgba2[5]);
+						xyz[2] += bx::toLinear(rgba2[6]);
+						xyz[3] +=              rgba2[7];
+
+						xyz[0] += bx::toLinear(rgba3[0]);
+						xyz[1] += bx::toLinear(rgba3[1]);
+						xyz[2] += bx::toLinear(rgba3[2]);
+						xyz[3] +=              rgba3[3];
+
+						xyz[0] += bx::toLinear(rgba3[4]);
+						xyz[1] += bx::toLinear(rgba3[5]);
+						xyz[2] += bx::toLinear(rgba3[6]);
+						xyz[3] +=              rgba3[7];
+
+						xyz[0] = bx::toGamma(xyz[0]/8.0f);
+						xyz[1] = bx::toGamma(xyz[1]/8.0f);
+						xyz[2] = bx::toGamma(xyz[2]/8.0f);
+						xyz[3] =             xyz[3]/8.0f;
+
+						bx::packRgba32F(dst, xyz);
+					}
+				}
+			}
+		}
+	}
+
+	void imageRgba32fDownsample2x2(void* _dst, uint32_t _width, uint32_t _height, uint32_t _depth, uint32_t _srcPitch, const void* _src)
+	{
+		imageRgba32fDownsample2x2Ref(_dst, _width, _height, _depth, _srcPitch, _src);
+	}
+
 	void imageRgba32fDownsample2x2NormalMapRef(void* _dst, uint32_t _width, uint32_t _height, uint32_t _srcPitch, uint32_t _dstPitch, const void* _src)
 	{
 		const uint32_t dstWidth  = _width/2;
@@ -1037,7 +1167,7 @@ namespace bimg
 
 		if (_dstFormat == _srcFormat)
 		{
-			bx::memCopy(_dst, _src, _width*_height*_depth*srcBpp/8);
+			bx::memCopy(_dst, _src, _width*_height*_depth*(srcBpp/8) );
 			return true;
 		}
 

+ 106 - 26
src/image_cubemap_filter.cpp

@@ -623,6 +623,7 @@ namespace bimg
 	void processFilterArea(
 		  float* _result
 		, const ImageContainer& _image
+		, uint8_t _lod
 		, const Aabb* _aabb
 		, const float* _dir
 		, float _specularPower
@@ -633,9 +634,6 @@ namespace bimg
 		float totalWeight = 0.0f;
 
 		const uint32_t bpp   = getBitsPerPixel(_image.m_format);
-		const uint32_t pitch = _image.m_width*bpp/8;
-		const float widthMinusOne = float(_image.m_width-1);
-		const float invWidth      = 1.0f/float(_image.m_width);
 
 		UnpackFn unpack = getUnpack(_image.m_format);
 
@@ -646,14 +644,18 @@ namespace bimg
 				continue;
 			}
 
-			const uint32_t minX = uint32_t(_aabb[side].m_min[0] * widthMinusOne);
-			const uint32_t maxX = uint32_t(_aabb[side].m_max[0] * widthMinusOne);
-			const uint32_t minY = uint32_t(_aabb[side].m_min[1] * widthMinusOne);
-			const uint32_t maxY = uint32_t(_aabb[side].m_max[1] * widthMinusOne);
-
 			ImageMip mip;
-			if (imageGetRawData(_image, side, 0, _image.m_data, _image.m_size, mip) )
+			if (imageGetRawData(_image, side, _lod, _image.m_data, _image.m_size, mip) )
 			{
+				const uint32_t pitch      = mip.m_width*bpp/8;
+				const float widthMinusOne = float(mip.m_width-1);
+				const float invWidth      = 1.0f/float(mip.m_width);
+
+				const uint32_t minX = uint32_t(_aabb[side].m_min[0] * widthMinusOne);
+				const uint32_t maxX = uint32_t(_aabb[side].m_max[0] * widthMinusOne);
+				const uint32_t minY = uint32_t(_aabb[side].m_min[1] * widthMinusOne);
+				const uint32_t maxY = uint32_t(_aabb[side].m_max[1] * widthMinusOne);
+
 				for (uint32_t yy = minY; yy <= maxY; ++yy)
 				{
 					const uint8_t* row = mip.m_data + yy*pitch;
@@ -713,35 +715,113 @@ namespace bimg
 		}
 	}
 
+	ImageContainer* imageGenerateMips(bx::AllocatorI* _allocator, const ImageContainer& _image)
+	{
+		if (_image.m_format != TextureFormat::RGBA8
+		&&  _image.m_format != TextureFormat::RGBA32F)
+		{
+			return NULL;
+		}
+
+		ImageContainer* output = imageAlloc(_allocator, _image.m_format, uint16_t(_image.m_width), uint16_t(_image.m_height), uint16_t(_image.m_depth), _image.m_numLayers, _image.m_cubeMap, true);
+
+		const uint32_t numMips   = output->m_numMips;
+		const uint32_t numLayers = output->m_numLayers;
+		const uint32_t numSides  = output->m_cubeMap ? 6 : 1;
+
+		for (uint32_t layer = 0; layer < numLayers; ++layer)
+		{
+			for (uint8_t side = 0; side < numSides; ++side)
+			{
+				ImageMip mip;
+				if (imageGetRawData(_image, uint16_t(layer*numSides + side), 0, _image.m_data, _image.m_size, mip) )
+				{
+					for (uint8_t lod = 0; lod < numMips; ++lod)
+					{
+						ImageMip srcMip;
+						imageGetRawData(*output, uint16_t(layer*numSides + side), lod == 0 ? 0 : lod-1, output->m_data, output->m_size, srcMip);
+
+						ImageMip dstMip;
+						imageGetRawData(*output, uint16_t(layer*numSides + side), lod, output->m_data, output->m_size, dstMip);
+
+						uint8_t* dstData = const_cast<uint8_t*>(dstMip.m_data);
+
+						if (0 == lod)
+						{
+							bx::memCopy(dstData, mip.m_data, mip.m_size);
+						}
+						else if (output->m_format == TextureFormat::RGBA8)
+						{
+							imageRgba8Downsample2x2(
+								  dstData
+								, srcMip.m_width
+								, srcMip.m_height
+								, srcMip.m_depth
+								, srcMip.m_width*4
+								, dstMip.m_width*4
+								, srcMip.m_data
+								);
+						}
+						else if (output->m_format == TextureFormat::RGBA32F)
+						{
+							imageRgba32fDownsample2x2(
+								  dstData
+								, srcMip.m_width
+								, srcMip.m_height
+								, srcMip.m_depth
+								, srcMip.m_width*16
+								, srcMip.m_data
+								);
+						}
+					}
+				}
+			}
+		}
+
+		return output;
+	}
+
 	ImageContainer* imageCubemapRadianceFilter(bx::AllocatorI* _allocator, const ImageContainer& _image, float _filterSize)
 	{
-		const uint32_t dstWidth = _image.m_width;
-		const uint32_t dstPitch = dstWidth*16;
-		const float invDstWidth = 1.0f / float(dstWidth);
+		ImageContainer* output = imageConvert(_allocator, TextureFormat::RGBA32F, _image, true);
+
+		if (1 >= output->m_numMips)
+		{
+			ImageContainer* temp = imageGenerateMips(_allocator, *output);
+			imageFree(output);
+			output = temp;
+		}
 
-		ImageContainer* output = imageAlloc(_allocator, TextureFormat::RGBA32F, uint16_t(dstWidth), uint16_t(dstWidth), 1, 1, true, true);
+		const uint32_t numMips = output->m_numMips;
 
 		for (uint8_t side = 0; side < 6; ++side)
 		{
-			ImageMip mip;
-			imageGetRawData(*output, side, 0, output->m_data, output->m_size, mip);
-
-			for (uint32_t yy = 0; yy < dstWidth; ++yy)
+			for (uint8_t lod = 0; lod < numMips; ++lod)
 			{
-				for (uint32_t xx = 0; xx < dstWidth; ++xx)
+				ImageMip mip;
+				imageGetRawData(*output, side, lod, output->m_data, output->m_size, mip);
+
+				const uint32_t dstWidth = mip.m_width;
+				const uint32_t dstPitch = dstWidth*16;
+				const float invDstWidth = 1.0f / float(dstWidth);
+
+				for (uint32_t yy = 0; yy < dstWidth; ++yy)
 				{
-					float* dstData = (float*)&mip. m_data[yy*dstPitch+xx*16];
+					for (uint32_t xx = 0; xx < dstWidth; ++xx)
+					{
+						float* dstData = (float*)&mip.m_data[yy*dstPitch+xx*16];
 
-					const float uu = float(xx)*invDstWidth*2.0f - 1.0f;
-					const float vv = float(yy)*invDstWidth*2.0f - 1.0f;
+						const float uu = float(xx)*invDstWidth*2.0f - 1.0f;
+						const float vv = float(yy)*invDstWidth*2.0f - 1.0f;
 
-					float dir[3];
-					texelUvToDir(dir, side, uu, vv);
+						float dir[3];
+						texelUvToDir(dir, side, uu, vv);
 
-					Aabb aabb[6];
-					calcFilterArea(aabb, dir, _filterSize);
+						Aabb aabb[6];
+						calcFilterArea(aabb, dir, _filterSize);
 
-					processFilterArea(dstData, _image, aabb, dir, 10.0f, 0.2f);
+						processFilterArea(dstData, *output, lod, aabb, dir, 10.0f, 0.2f);
+					}
 				}
 			}
 		}

+ 1 - 1
tools/texturec/texturec.cpp

@@ -1069,7 +1069,7 @@ int main(int _argc, const char* _argv[])
 				bimg::imageWriteHdr(&writer
 					, mip.m_width
 					, mip.m_height
-					, mip.m_width*8
+					, mip.m_width*getBitsPerPixel(mip.m_format)/8
 					, mip.m_data
 					, output->m_format
 					, false