Beispiel #1
0
bool Image::initWithS3TCData(const unsigned char * data, ssize_t dataLen)
{
	const uint32_t FOURCC_DXT1 = makeFourCC('D', 'X', 'T', '1');
	const uint32_t FOURCC_DXT3 = makeFourCC('D', 'X', 'T', '3');
	const uint32_t FOURCC_DXT5 = makeFourCC('D', 'X', 'T', '5');

	/* load the .dds file */

	S3TCTexHeader *header = (S3TCTexHeader *)data;
	unsigned char *pixelData = static_cast<unsigned char*>(malloc((dataLen - sizeof(S3TCTexHeader)) * sizeof(unsigned char)));
	memcpy((void *)pixelData, data + sizeof(S3TCTexHeader), dataLen - sizeof(S3TCTexHeader));

	_width = header->ddsd.width;
	_height = header->ddsd.height;
	_numberOfMipmaps = MAX(1, header->ddsd.DUMMYUNIONNAMEN2.mipMapCount); //if dds header reports 0 mipmaps, set to 1 to force correct software decoding (if needed).
	_dataLen = 0;
	int blockSize = (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC) ? 8 : 16;

	/* calculate the dataLen */

	int width = _width;
	int height = _height;

	if (supportsS3TC)  //compressed data length
	{
		_dataLen = dataLen - sizeof(S3TCTexHeader);
		_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
		memcpy((void *)_data, (void *)pixelData, _dataLen);
	}
	else                                               //decompressed data length
	{
		for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
		{
			if (width == 0) width = 1;
			if (height == 0) height = 1;

			_dataLen += (height * width * 4);

			width >>= 1;
			height >>= 1;
		}
		_data = static_cast<unsigned char*>(malloc(_dataLen * sizeof(unsigned char)));
	}

	/* if hardware supports s3tc, set pixelformat before loading mipmaps, to support non-mipmapped textures  */
	if (supportsS3TC)
	{   //decode texture through hardware

		if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
		{
			_renderFormat = Texture2D::PixelFormat::S3TC_DXT1;
		}
		else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
		{
			_renderFormat = Texture2D::PixelFormat::S3TC_DXT3;
		}
		else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
		{
			_renderFormat = Texture2D::PixelFormat::S3TC_DXT5;
		}
	}
	else { //will software decode
		_renderFormat = Texture2D::PixelFormat::RGBA8888;
	}

	/* load the mipmaps */

	int encodeOffset = 0;
	int decodeOffset = 0;
	width = _width;  height = _height;

	for (int i = 0; i < _numberOfMipmaps && (width || height); ++i)
	{
		if (width == 0) width = 1;
		if (height == 0) height = 1;

		int size = ((width + 3) / 4)*((height + 3) / 4)*blockSize;

		if (supportsS3TC)
		{   //decode texture through hardware
			_mipmaps[i].address = (unsigned char *)_data + encodeOffset;
			_mipmaps[i].len = size;
		}
		else
		{   //if it is not gles or device do not support S3TC, decode texture by software

			OUTPUT_LOG("cocos2d: Hardware S3TC decoder not present. Using software decoder");

			int bytePerPixel = 4;
			unsigned int stride = width * bytePerPixel;

			std::vector<unsigned char> decodeImageData(stride * height);
			if (FOURCC_DXT1 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
			{
				s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT1);
			}
			else if (FOURCC_DXT3 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
			{
				s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT3);
			}
			else if (FOURCC_DXT5 == header->ddsd.DUMMYUNIONNAMEN4.ddpfPixelFormat.fourCC)
			{
				s3tc_decode(pixelData + encodeOffset, &decodeImageData[0], width, height, S3TCDecodeFlag::DXT5);
			}

			_mipmaps[i].address = (unsigned char *)_data + decodeOffset;
			_mipmaps[i].len = (stride * height);
			memcpy((void *)_mipmaps[i].address, (void *)&decodeImageData[0], _mipmaps[i].len);
			decodeOffset += stride * height;
		}

		encodeOffset += size;
		width >>= 1;
		height >>= 1;
	}

	/* end load the mipmaps */

	if (pixelData != nullptr)
	{
		free(pixelData);
	};

	return true;
}
Beispiel #2
0
uint32_t ShaderManager::at(const std::string& filename)
{
/*
	filename suffix can be one of the followings values, where they are named after shader type.
		.vert for a vertex shader
		.tesc for a tessellation control shader
		.tese for a tessellation evaluation shader
		.geom for a geometry shader
		.frag for a fragment shader
		.comp for a compute shader
*/
	size_t length = filename.length();
	if(length < std::string("*.type").length())
		return 0;

	const auto it = shader_id_map.find(filename);
	if(it != shader_id_map.end())
		return it->second;

	const char* p = filename.c_str() + filename.length();
	p -= 5;
	if(*p != '.')
	{
		slog.w(TAG, "filename [%s] suffix doesn't belongs to {'vert', 'tesc', 'tese', 'geom', 'frag', 'comp'}", filename.c_str());
		return 0;
	}

	int type = *reinterpret_cast<const int*>(p + 1);

#if __cplusplus >= 201103L
	constexpr uint32_t VERT = makeFourCC('v', 'e', 'r', 't');
	constexpr uint32_t TESC = makeFourCC('t', 'e', 's', 'c');
	constexpr uint32_t TESE = makeFourCC('t', 'e', 's', 'e');
	constexpr uint32_t GEOM = makeFourCC('g', 'e', 'o', 'm');
	constexpr uint32_t FRAG = makeFourCC('f', 'r', 'a', 'g');
	constexpr uint32_t COMP = makeFourCC('c', 'o', 'm', 'p');
#else
	#define VERT makeFourCC('v', 'e', 'r', 't')
	#define TESC makeFourCC('t', 'e', 's', 'c')
	#define TESE makeFourCC('t', 'e', 's', 'e')
	#define GEOM makeFourCC('g', 'e', 'o', 'm')
	#define FRAG makeFourCC('f', 'r', 'a', 'g')
	#define COMP makeFourCC('c', 'o', 'm', 'p')
#endif

	Shader* shader = nullptr;
	switch(type)
	{
	case VERT: shader = new(std::nothrow) VertexShader();         break;
	case TESC: shader = new(std::nothrow) TessControlShader();    break;
	case TESE: shader = new(std::nothrow) TessEvaluationShader(); break;
	case GEOM: shader = new(std::nothrow) GeometryShader();       break;
	case FRAG: shader = new(std::nothrow) FragmentShader();       break;
	case COMP: shader = new(std::nothrow) ComputeShader();        break;
	default:   assert(false && "unknown shader type");            break;
	}

	shader->loadFromFile(filename);
	bool flag = shader->compile();
	assert(flag);  // fast fail

	uint32_t id = shader->getId();
	shader_id_map[filename] = id;

	delete shader;
	return id;
}