Beispiel #1
0
// Pack textures into a larger one and return it. outPositions returns the new positions of the textures in the order they appeared in the array
irr::video::ITexture* CMeshCombiner::packTextures(irr::video::IVideoDriver *driver, irr::core::array<irr::video::ITexture*> textures, irr::core::array<irr::core::position2di> &outPositions) {
	irr::video::ITexture* newTexture;
	irr::core::array<irr::core::rect<irr::u32>> textureRects;
	for (int x = 0; x < textures.size(); x++) {
		textureRects.push_back(irr::core::rect<irr::u32>(0,0,textures[x]->getSize().Width+mTexturePadding,textures[x]->getSize().Height+mTexturePadding));
	}

	irr::core::dimension2du textureSize = findOptimalPackingArea(textureRects);
	irr::core::array<irr::core::array<CRectPacker::SPacked>> packed;
	CRectPacker packer;
	packer.pack(textureRects,packed,textureSize.Height);
	irr::video::IImage* packedImage = driver->createImage(textures[0]->getColorFormat(),textureSize);
	irr::video::IImage** textureImages = new irr::video::IImage*[textures.size()];
	for (int x = 0; x < textures.size(); x++) {
		textureImages[x] = driver->createImage(textures[x],irr::core::vector2di(0,0),textures[x]->getSize());
		outPositions.push_back(irr::core::position2di(0,0));
	}
	for (int x = 0; x < packed[0].size(); x++) {
		irr::video::IImage* im = textureImages[packed[0][x].id];
		int xPos = packed[0][x].pos.UpperLeftCorner.X+mTexturePadding/2;
		int yPos = packed[0][x].pos.UpperLeftCorner.Y+mTexturePadding/2;
		im->copyTo(packedImage,irr::core::vector2di(xPos,yPos));
		if (mTexturePaddingTechnique == ETPT_EXPAND) {
			for (int y = 0; y < mTexturePadding/2; y++) {
				im->copyTo(packedImage,irr::core::vector2di(xPos-y,yPos),irr::core::rect<irr::s32>(0,0,1,textures[packed[0][x].id]->getSize().Height));
				im->copyTo(packedImage,irr::core::vector2di(xPos+y+textures[packed[0][x].id]->getSize().Width,yPos),irr::core::rect<irr::s32>(0,0,1,textures[packed[0][x].id]->getSize().Height));			
				im->copyTo(packedImage,irr::core::vector2di(xPos,yPos-y),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,1));
				im->copyTo(packedImage,irr::core::vector2di(xPos,yPos+y+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,1));		
			}
		}
		else if (mTexturePaddingTechnique == ETPT_TILE) {
			im->copyTo(packedImage,irr::core::vector2di(xPos,yPos-mTexturePadding/2),irr::core::rect<irr::s32>(0,textures[packed[0][x].id]->getSize().Height-mTexturePadding/2,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,mTexturePadding/2));
			im->copyTo(packedImage,irr::core::vector2di(xPos-mTexturePadding/2,yPos),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-mTexturePadding/2,0,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos),irr::core::rect<irr::s32>(0,0,mTexturePadding/2,textures[packed[0][x].id]->getSize().Height));		
			im->copyTo(packedImage,irr::core::vector2di(xPos-mTexturePadding/2,yPos-mTexturePadding/2),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-mTexturePadding/2,textures[packed[0][x].id]->getSize().Height-mTexturePadding/2,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos-mTexturePadding/2),irr::core::rect<irr::s32>(0,textures[packed[0][x].id]->getSize().Height-mTexturePadding/2,mTexturePadding/2,textures[packed[0][x].id]->getSize().Height));		
			im->copyTo(packedImage,irr::core::vector2di(xPos-mTexturePadding/2,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-mTexturePadding/2,0,textures[packed[0][x].id]->getSize().Width,mTexturePadding/2));		
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,mTexturePadding/2,mTexturePadding/2));			
		}
		outPositions[packed[0][x].id].set(xPos,yPos);
	}
	irr::core::stringc textureName = "PackedTexture";
	newTexture = driver->addTexture(textureName, packedImage);
	newTexture->regenerateMipMapLevels();
	textureName += globalPackedTextureCount;
	globalPackedTextureCount++;
	return newTexture;
}
Beispiel #2
0
// Pack textures into a larger one and return it. outPositions returns the new positions of the textures in the order they appeared in the array
irr::video::ITexture* CMeshCombiner::packTextures(irr::video::IVideoDriver *driver, irr::core::array<irr::video::ITexture*> textures, irr::core::array<irr::core::position2di> &outPositions) {
	
	irr::video::ITexture* newTexture;
	int area = 0;
	for (int x = 0; x < textures.size(); x++) {
		area += textures[x]->getSize().getArea();
	}
	float squareDim = sqrt((float)(area*1.5));
	int nearestPow2 = ceil(log((float)squareDim)/log(2.0f));
	int safePadding = pow(2.0f,nearestPow2)/32+4;
	if (safePadding == 0)
		safePadding = 1;

	irr::core::array<irr::core::rect<irr::u32>> textureRects;
	for (int x = 0; x < textures.size(); x++) {
		textureRects.push_back(irr::core::rect<irr::u32>(0,0,textures[x]->getSize().Width+safePadding,textures[x]->getSize().Height+safePadding));
	}

	irr::core::dimension2du textureSize = findOptimalPackingArea(textureRects);

	// This is used to tell if an actual texture occupies a certain pixel
	bool *occupied = new bool[textureSize.getArea()];
	for (int i = 0; i < textureSize.getArea(); i++)
		occupied[i] = false;

	irr::core::array<irr::core::array<CRectPacker::SPacked>> packed;
	CRectPacker packer;
	packer.pack(textureRects,packed,textureSize.Height);
	irr::video::IImage* packedImage = driver->createImage(textures[0]->getColorFormat(),textureSize);
	irr::video::IImage** textureImages = new irr::video::IImage*[textures.size()];
	for (int x = 0; x < textures.size(); x++) {
		textureImages[x] = driver->createImage(textures[x],irr::core::vector2di(0,0),textures[x]->getSize());
		outPositions.push_back(irr::core::position2di(0,0));
	}
	for (int x = 0; x < packed[0].size(); x++) {
		irr::video::IImage* im = textureImages[packed[0][x].id];
		int xPos = packed[0][x].pos.UpperLeftCorner.X+safePadding/2;
		int yPos = packed[0][x].pos.UpperLeftCorner.Y+safePadding/2;
		int width = packed[0][x].pos.getWidth();
		int height = packed[0][x].pos.getWidth();

		// Anywhere the texture exists, mark the pixel as occupied
		for (int u = xPos; u < xPos+width; u++) {
			for (int v = yPos; v < yPos+height; v++) {
				occupied[u+v*textureSize.Width] = true;
			}
		}

		im->copyTo(packedImage,irr::core::vector2di(xPos,yPos));
		if (mTexturePaddingTechnique == ETPT_EXPAND) {
			for (int y = 0; y < safePadding/2; y++) {
				im->copyTo(packedImage,irr::core::vector2di(xPos-y,yPos),irr::core::rect<irr::s32>(0,0,1,textures[packed[0][x].id]->getSize().Height));
				im->copyTo(packedImage,irr::core::vector2di(xPos+y+textures[packed[0][x].id]->getSize().Width,yPos),irr::core::rect<irr::s32>(0,0,1,textures[packed[0][x].id]->getSize().Height));			
				im->copyTo(packedImage,irr::core::vector2di(xPos,yPos-y),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,1));
				im->copyTo(packedImage,irr::core::vector2di(xPos,yPos+y+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,1));		
			}
		}
		else if (mTexturePaddingTechnique == ETPT_TILE) {
			im->copyTo(packedImage,irr::core::vector2di(xPos,yPos-safePadding/2),irr::core::rect<irr::s32>(0,textures[packed[0][x].id]->getSize().Height-safePadding/2,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,textures[packed[0][x].id]->getSize().Width,safePadding/2));
			im->copyTo(packedImage,irr::core::vector2di(xPos-safePadding/2,yPos),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-safePadding/2,0,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos),irr::core::rect<irr::s32>(0,0,safePadding/2,textures[packed[0][x].id]->getSize().Height));		
			im->copyTo(packedImage,irr::core::vector2di(xPos-safePadding/2,yPos-safePadding/2),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-safePadding/2,textures[packed[0][x].id]->getSize().Height-safePadding/2,textures[packed[0][x].id]->getSize().Width,textures[packed[0][x].id]->getSize().Height));
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos-safePadding/2),irr::core::rect<irr::s32>(0,textures[packed[0][x].id]->getSize().Height-safePadding/2,safePadding/2,textures[packed[0][x].id]->getSize().Height));		
			im->copyTo(packedImage,irr::core::vector2di(xPos-safePadding/2,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(textures[packed[0][x].id]->getSize().Width-safePadding/2,0,textures[packed[0][x].id]->getSize().Width,safePadding/2));		
			im->copyTo(packedImage,irr::core::vector2di(xPos+textures[packed[0][x].id]->getSize().Width,yPos+textures[packed[0][x].id]->getSize().Height),irr::core::rect<irr::s32>(0,0,safePadding/2,safePadding/2));			
		}
		outPositions[packed[0][x].id].set(xPos,yPos);
	}

	// Create mipmap data
	int mipmapSize = 0;
	int lowestDim = (packedImage->getDimension().Width < packedImage->getDimension().Height) ? packedImage->getDimension().Width : packedImage->getDimension().Height;
	int highestDim = (packedImage->getDimension().Width > packedImage->getDimension().Height) ? packedImage->getDimension().Width : packedImage->getDimension().Height;
	int mipmapCount = 0;
	for (mipmapCount = 0; lowestDim > 1; lowestDim/=2, highestDim /=2, mipmapCount++) {
		if (mipmapCount >= 1)
			mipmapSize += lowestDim*highestDim;
	}
	irr::u8* mipmapData = new irr::u8[mipmapSize*4];
	irr::u8* imageData = (irr::u8*)packedImage->lock();

	// To prevent bleeding artifacts, do NOT blend any unoccupied pixels with occupied pixels. If an unoccupied pixel would be blended with an occupied one, use only occupied pixels instead
	int currentIndex = 0;
	for (int i = 0; i < mipmapCount; i++) {

		int blendSize = pow(2.0,i+1);
		int currentLevelWidth = packedImage->getDimension().Width/blendSize;
		int currentLevelHeight = packedImage->getDimension().Height/blendSize;



		// Create mipmap of current level
		for (int x = 0; x < currentLevelWidth; x++) {
			for (int y = 0; y < currentLevelHeight; y++) {

				// Check to see if it has any occupied pixels that will be blended
				int occupiedPixelR, occupiedPixelG, occupiedPixelB, occupiedPixelA;
				occupiedPixelR = occupiedPixelG = occupiedPixelB = occupiedPixelA = 0;
				int occupiedPixelCount = 0;

				int unoccupiedPixelR, unoccupiedPixelG, unoccupiedPixelB, unoccupiedPixelA;
				unoccupiedPixelR = unoccupiedPixelG = unoccupiedPixelB = unoccupiedPixelA = 0;
				int unoccupiedPixelCount = 0;


				/*for (int u = x*blendSize; u < std::min(x*blendSize+blendSize,(int)packedImage->getDimension().Width); u++) {
					for (int v = y*blendSize; v < std::min(y*blendSize+blendSize,(int)packedImage->getDimension().Height); v++) {
						int realX = u*4;
						int realY = v*4;
						if (!occupied[u+v*packedImage->getDimension().Width]) {
							unoccupiedPixelB += imageData[realX+realY*packedImage->getDimension().Width];
							unoccupiedPixelG += imageData[realX+realY*packedImage->getDimension().Width+1];
							unoccupiedPixelR += imageData[realX+realY*packedImage->getDimension().Width+2];
							unoccupiedPixelA += imageData[realX+realY*packedImage->getDimension().Width+3];
							unoccupiedPixelCount++;
						}
						else {
							occupiedPixelB += imageData[realX+realY*packedImage->getDimension().Width];
							occupiedPixelG += imageData[realX+realY*packedImage->getDimension().Width+1];
							occupiedPixelR += imageData[realX+realY*packedImage->getDimension().Width+2];
							occupiedPixelA += imageData[realX+realY*packedImage->getDimension().Width+3];
							occupiedPixelCount++;
						}

					}
				}*/

				if (occupiedPixelCount == 0 && unoccupiedPixelCount != 0) {
					unoccupiedPixelB /= unoccupiedPixelCount;
					unoccupiedPixelG /= unoccupiedPixelCount;
					unoccupiedPixelR /= unoccupiedPixelCount;
					unoccupiedPixelA /= unoccupiedPixelCount;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth] = unoccupiedPixelB;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+1] = unoccupiedPixelG;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+2] = unoccupiedPixelR;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+3] = unoccupiedPixelA;
				}

				else if (occupiedPixelCount != 0) {
					occupiedPixelB /= occupiedPixelCount;
					occupiedPixelG /= occupiedPixelCount;
					occupiedPixelR /= occupiedPixelCount;
					occupiedPixelA /= occupiedPixelCount;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth] = occupiedPixelB;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+1] = occupiedPixelG;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+2] = occupiedPixelR;
					mipmapData[currentIndex+x*4+y*4*currentLevelWidth+3] = occupiedPixelA;
				}

			}
		}

		currentIndex += (currentLevelWidth*currentLevelHeight)*4;
	}

	packedImage->unlock();

	irr::core::stringc textureName = "PackedTexture";
	newTexture = driver->addTexture(textureName, packedImage, mipmapData);
	textureName += globalPackedTextureCount;
	globalPackedTextureCount++;
	delete [] occupied;
	for (int x = 0; x < textures.size(); x++) {
		textureImages[x]->drop();
	}
	delete [] textureImages;
	packedImage->drop();
	return newTexture;
}