//-----------------------------------------------------------------------
void AtlasImageTool::correctAlpha (Ogre::Image& image, Ogre::Real alphaCorrection)
{
	size_t numPixels = image.getWidth() * image.getHeight();
	size_t pointer = 0;
	for (size_t i = 0; i < numPixels; ++i)
	{
		Ogre::ColourValue colour;
		Ogre::PixelUtil::unpackColour(&colour, image.getFormat(), (image.getData() + pointer));
		colour.a *= alphaCorrection;
		Ogre::PixelUtil::packColour(colour, image.getFormat(), (image.getData() + pointer));
		pointer += Ogre::PixelUtil::getNumElemBytes(image.getFormat());
	}
}
Example #2
0
void gkTextureLoader::loadResource(Ogre::Resource* resource)
{
	Ogre::Texture* texture = static_cast<Ogre::Texture*>(resource);

	if (!m_stream)
	{
		gkPrintf("Warning: Skipping image %s no packed file information is present!", texture->getName().c_str());
		return;
	}

	Ogre::DataStreamPtr stream(OGRE_NEW Ogre::MemoryDataStream(m_stream->ptr(), m_stream->size()));

	Ogre::Image ima;
	ima.load(stream);

	texture->setUsage(Ogre::TU_DEFAULT);
	texture->setTextureType(Ogre::TEX_TYPE_2D);
	texture->setNumMipmaps(gkEngine::getSingleton().getUserDefs().defaultMipMap);
	texture->setWidth(ima.getWidth());
	texture->setHeight(ima.getHeight());
	texture->setDepth(ima.getDepth());
	texture->setFormat(ima.getFormat());

	Ogre::ConstImagePtrList ptrs;
	ptrs.push_back(&ima);
	texture->_loadImages(ptrs);
}
//----------------------------------------------------------------------------//
Texture* OgreImageCodec::load(const RawDataContainer& data, Texture* result)
{
    using namespace Ogre;

    // wrap the buffer of the RawDataContainer with an Ogre::MemoryDataStream.
    DataStreamPtr stream(
        new MemoryDataStream(
            const_cast<void*>(static_cast<const void*>(data.getDataPtr())),
            data.getSize(), false));

    // load the image
    Ogre::Image image;
    image.load(stream);

    // discover the pixel format and number of pixel components
    Texture::PixelFormat format;
    int components;
    switch (image.getFormat())
    {
        case PF_R8G8B8:
            format = Texture::PF_RGB;
            components = 3;
            break;

        case PF_A8R8G8B8:
            format = Texture::PF_RGBA;
            components = 4;
            break;

        default:
            throw FileIOException("OgreImageCodec::load: File data was of an "
                                  "unsupported format.");
            break;
    }

    // do the old switcharoo on R and B...
    // (we could 'fix' this in the CEGUI::OgreTexture, but that would break all
    // the other ImageCodecs when used with the Ogre renderer, hence we don't)
    uchar* dat = image.getData();
    for (uint j = 0; j < image.getHeight(); ++j)
    {
        for (uint i = 0; i < image.getWidth(); ++i)
        {
            uchar tmp = dat[i * components + 0];
            dat[i * components + 0] = dat[i * components + 2];
            dat[i * components + 2] = tmp;
        }

        dat += image.getRowSpan();
    }

    // load the resulting image into the texture
    result->loadFromMemory(image.getData(),
                           Size(image.getWidth(),
                                image.getHeight()),
                           format);

    return result;
}
//-----------------------------------------------------------------------
void AtlasImageTool::interpolate (Ogre::Image& interpolatedImage, 
								  Ogre::Image& firstImage, 
								  Ogre::Image& nextImage, 
								  Ogre::Real fraction)
{
	size_t numPixels = interpolatedImage.getWidth() * interpolatedImage.getHeight();
	size_t pointer = 0;
	for (size_t i = 0; i < numPixels; ++i)
	{
		Ogre::ColourValue firstColour;
		Ogre::ColourValue nextColour;
		Ogre::ColourValue interpolatedColour;
		Ogre::PixelUtil::unpackColour(&firstColour, firstImage.getFormat(), (firstImage.getData() + pointer));
		Ogre::PixelUtil::unpackColour(&nextColour, nextImage.getFormat(), (nextImage.getData() + pointer));
		interpolatedColour = firstColour + fraction * (nextColour - firstColour);
		Ogre::PixelUtil::packColour(interpolatedColour, interpolatedImage.getFormat(), (interpolatedImage.getData() + pointer));
		pointer += Ogre::PixelUtil::getNumElemBytes(interpolatedImage.getFormat());
	}
}
Example #5
0
//----------------------------------------------------------------------------------------
QImage ImageConverter::fromOgreImage(const Ogre::Image& image)
{
    if (!Ogre::PixelUtil::isAccessible(image.getFormat()))
        return _imageFromRenderTarget(image);

    size_t size = Ogre::PixelUtil::getMemorySize(mWidth, mHeight, 1, Ogre::PF_A8R8G8B8);
    unsigned char *dataptr = OGRE_ALLOC_T(unsigned char, size, Ogre::MEMCATEGORY_GENERAL);

    Ogre::PixelBox pixbox(mWidth, mHeight, 1, Ogre::PF_A8R8G8B8, dataptr);
    Ogre::Image::scale(image.getPixelBox(), pixbox);
    pixbox.setConsecutive();

    QImage shallowImg(dataptr, pixbox.getWidth(), pixbox.getHeight(), QImage::Format_ARGB32);

    // perform deep copy otherwise data lost upon freeing dataptr
    QImage deepImg = shallowImg.copy();
    OGRE_FREE(dataptr, Ogre::MEMCATEGORY_GENERAL);

    return deepImg;
}
	//------------------------------------------------------
	void TextureAtlas::build() {
		if (!mIsDirty)
			return;

		bool fitted;

		size_t area = 0;

		// build the fonts (if this didn't happen already)
		// so we'll be sure the glyphs are there to be atlassed
		FontSet::iterator fit = mMyFonts.begin();

		while (fit != mMyFonts.end()) {
			FontDrawSource* fdsp = *fit++;

			if (!fdsp->isBuilt())
				fdsp->build();
		}

		// First, we sort by size of the DrawSource
		mMyDrawSources.sort(DrawSourceLess());

		// now try to allocate all the draw sources. If we fail, grow and try again
		do {
			fitted = true;
			area = 0;

			// try to fit
			DrawSourceList::iterator it = mMyDrawSources.begin();

			while (it != mMyDrawSources.end()) {
				
				const DrawSourcePtr& ds = *it++;

				const PixelSize& ps = ds->getPixelSize();
				area += ps.getPixelArea();
				
				LOG_VERBOSE("TextureAtlas: (%s) Trying to place %d x %d (%d -> %d)", mAtlasName.c_str(), ps.width, ps.height, ps.getPixelArea(), area);

				// try to allocate
				FreeSpaceInfo* fsi = mAtlasAllocation->allocate(ps.width, ps.height);

				if (fsi) {
					ds->setPlacementPtr(fsi);
				} else {
					fitted = false;
					break;
				}
			}
			// fitted?

			if (!fitted) // nope - Enlarge!
				enlarge(area);
		} while (!fitted);
		
		LOG_INFO("TextureAtlas: (%s) Creating atlas with dimensions %d x %d", mAtlasName.c_str(), mAtlasSize.width, mAtlasSize.height);

		if (mTexture.isNull())
			prepareResources();
		// TODO: Reallocate the texture here if needed!
		
		Ogre::HardwarePixelBufferSharedPtr pixelBuffer = mTexture->getBuffer();
		pixelBuffer->lock(Ogre::HardwareBuffer::HBL_DISCARD);
		
		const Ogre::PixelBox& targetBox = pixelBuffer->getCurrentLock();
		
		size_t pixelsize = Ogre::PixelUtil::getNumElemBytes(targetBox.format);
		size_t rowsize = targetBox.rowPitch * pixelsize;

		Ogre::uint8* dstData = static_cast<Ogre::uint8*>(targetBox.data);

		// We'll iterate over all draw sources, painting the pixels onto the allocated space
		DrawSourceList::iterator it = mMyDrawSources.begin();

		while (it != mMyDrawSources.end()) {
			const DrawSourcePtr& ds = *it++;

			// render all pixels into the right place
			FreeSpaceInfo* fsi = reinterpret_cast<FreeSpaceInfo*>(ds->getPlacementPtr());
			
			assert(fsi);

			// render into the specified place
			unsigned char* conversionBuf = NULL;
			

			const PixelSize& dps = ds->getPixelSize();
			Ogre::Image* img = ds->getImage();
			Ogre::PixelBox srcPixels = img->getPixelBox();
			
			// convert if the source data don't match
			if(img->getFormat() != Ogre::PF_BYTE_BGRA) {
					conversionBuf = new unsigned char[img->getWidth() * img->getHeight() * pixelsize];
					Ogre::PixelBox convPixels(Ogre::Box(0, 0, dps.width, dps.height), Ogre::PF_BYTE_BGRA, conversionBuf);
					Ogre::PixelUtil::bulkPixelConversion(srcPixels, convPixels);
					srcPixels = convPixels;
			}

			size_t srcrowsize = srcPixels.rowPitch * pixelsize;

			Ogre::uint8* srcData = static_cast<Ogre::uint8*>(srcPixels.data);
			
			// TODO: we're always handling 32bit data, so we could as well transfer 4 bytes each iteration instead of one (speedup)
			for(size_t row = 0; row < dps.height; row++) {
					for(size_t col = 0; col < srcrowsize; col++) {
							dstData[((row + fsi->y) * rowsize) + (fsi->x * pixelsize) + col] =
								srcData[(row * srcrowsize) + col];
					}
			}

			delete[] conversionBuf;
			
			// Convert the full draw source pixel coordinates to the atlas contained ones (initializes the texturing coordinates transform)
			ds->atlas(mMaterial, fsi->x, fsi->y, mAtlasSize.width, mAtlasSize.height);
		}

		 // for debug, write the texture to a file
		/*unsigned char *readrefdata = static_cast<unsigned char*>(targetBox.data);		
				     
		Ogre::Image img;
		img = img.loadDynamicImage (readrefdata, mTexture->getWidth(),
		    mTexture->getHeight(), mTexture->getFormat());	
		img.save(mAtlasName + ".png");*/

		// and close the pixel buffer of the atlas at the end
		pixelBuffer->unlock();
		mIsDirty = false;
	}
    bool MiniMapMaker::outputTextures(void)
    {
        // 如果需要(纹理大小改变了或第一次输出文件时),就重建render texture
        if (mNeedRecreate)
        {
            destroy();
            init();
        }

        mTempOutputFileNames.clear();

        static const String TEMP_GROUP_NAME = "#TEMP#";

        // 创建临时的资源组
        Ogre::ResourceGroupManager& rgm = Ogre::ResourceGroupManager::getSingleton();
        rgm.addResourceLocation(mPath, "FileSystem", TEMP_GROUP_NAME, false);

        // 合并所有物体的包围盒
        Ogre::AxisAlignedBox aabb;
        Ogre::SceneManager::MovableObjectIterator itm =
            mManipulator->getSceneManager()->getMovableObjectIterator(Ogre::EntityFactory::FACTORY_TYPE_NAME);
        while (itm.hasMoreElements())
        {
            Ogre::MovableObject* movable = itm.getNext();
            aabb.merge(movable->getWorldBoundingBox(true));
        }

        mCamera->setFarClipDistance(mCamera->getNearClipDistance() + 2 * (aabb.getMaximum().y - aabb.getMinimum().y ));
        mCamera->setNearClipDistance(mTileSize/2);

        // 设置摄像机的高度
        Real yPos = mCamera->getNearClipDistance() + aabb.getMaximum().y;
        
        TerrainData* terrainData = mManipulator->getTerrainData();
        assert (terrainData);

        float terrainHeight = terrainData->mMaxZ - terrainData->mMinZ;
        float terrainWidth = terrainData->mMaxX - terrainData->mMinX;

        // 投影的真正面积
        Real projectSize = 0.0f;

        // 最终切割成小块纹理的块数
        int xIndex = 0;
        int zIndex = 0;

        Ogre::Vector3 originPoint(Ogre::Vector3::ZERO);

        if (mUseRealCameraAngle)
        {
            float outerSquareWidth = 0.0f;
            float outerSquareHeight = 0.0f;

            Ogre::Radian alphaAngle = Ogre::Math::ATan( Ogre::Math::Abs(mMoveZDir.z / mMoveZDir.x) );

            switch (mCameraDirQuadrant)
            {
            case WestNorth :
                {
                    float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight;
                    float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth;
                    outerSquareWidth = leftWidth + rightWidth;

                    float topHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight;
                    float bottomHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth;

                    outerSquareHeight = topHeight + bottomHeight;

                    originPoint = Ogre::Vector3(terrainData->mMinX,0,terrainData->mMinZ) +
                        (-mMoveZDir * leftWidth);

                    float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle);

                    originPoint.x += (mInvertCameraDir * projectOffset ).x;
                    originPoint.z += (mInvertCameraDir * projectOffset ).z;

                    break;
                }
            case EastNorth :
                {
                    float leftWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth;
                    float rightWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight;
                    outerSquareWidth = leftWidth + rightWidth;

                    float topHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight;
                    float bottomHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth;

                    outerSquareHeight = topHeight + bottomHeight;

                    originPoint = Ogre::Vector3(terrainData->mMaxX,0,terrainData->mMinZ) +
                        (-mMoveZDir * leftWidth);

                    float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle);

                    originPoint.x += (mInvertCameraDir * projectOffset ).x;
                    originPoint.z += (mInvertCameraDir * projectOffset ).z;

                    break;
                }
            case EastSouth :
                {
                    float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight;
                    float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth;
                    outerSquareWidth = leftWidth + rightWidth;

                    float topHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth;
                    float bottomHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight;

                    outerSquareHeight = topHeight + bottomHeight;

                    originPoint = Ogre::Vector3(terrainData->mMaxX,0,terrainData->mMaxZ) +
                        (-mMoveZDir * topHeight);

                    float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle);

                    originPoint.x += (mInvertCameraDir * projectOffset ).x;
                    originPoint.z += (mInvertCameraDir * projectOffset ).z;

                    break;
                }
            case WestSouth :
                {
                    float leftWidth = Ogre::Math::Sin(alphaAngle) * terrainHeight;
                    float rightWidth = Ogre::Math::Cos(alphaAngle) * terrainWidth;
                    outerSquareWidth = leftWidth + rightWidth;

                    float topHeight = Ogre::Math::Sin(alphaAngle) * terrainWidth;
                    float bottomHeight = Ogre::Math::Cos(alphaAngle) * terrainHeight;

                    outerSquareHeight = topHeight + bottomHeight;

                    originPoint = Ogre::Vector3(terrainData->mMinX,0,terrainData->mMaxZ) +
                        (-mMoveZDir * rightWidth);

                    float projectOffset = yPos / Ogre::Math::Tan(mCamDirAngle);

                    originPoint.x += (mInvertCameraDir * projectOffset ).x;
                    originPoint.z += (mInvertCameraDir * projectOffset ).z;

                    break;
                }

            default:
                {
                    OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR,
                        " wrong camera dir " + Ogre::StringConverter::toString(mCameraDir),
                        "MiniMapMaker::outputTextures");

                    break;
                }
            }

            // 计算投影的长度
            Real factor = Ogre::Math::Sin(mCamDirAngle);

            if (factor > 0.0f && factor != 1.0f)
                projectSize = mTileSize / factor;

            // 根据当前场景的大小,计算需要的分块数
            xIndex = Ogre::Math::Ceil( (outerSquareWidth) / mTileSize ) + 1;
            zIndex = Ogre::Math::Ceil( (outerSquareHeight) / projectSize ) + 1;
        }
        else
        {
            xIndex = Ogre::Math::Ceil( (terrainData->mMaxX - terrainData->mMinX) / mTileSize ) + 1;
            zIndex = Ogre::Math::Ceil( (terrainData->mMaxZ - terrainData->mMinZ) / mTileSize ) + 1;

            originPoint.x = terrainData->mMinX;
            originPoint.z = terrainData->mMinZ;
        }

        // 计算最终的mini map的大小
        uint miniMapWidth = xIndex * mTexWidth;
        uint miniMapHeight = zIndex * mTexHeight;

        if ( miniMapWidth > 10000 || miniMapHeight > 10000 )
        {
            mLastErrorString = "texture size is out of range!";
            return false;
        }
        // 创建mini map所需的内存空间
        uchar* miniMapData = new uchar[miniMapWidth * miniMapHeight * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat)];

        //// 初始的摄像机位置
        Real xPos = originPoint.x;
        Real zPos = originPoint.z;

        for ( int i=0; i<xIndex; ++i )
        {
            for ( int j=0; j<zIndex; ++j )
            {
                // 设置摄像机位置,并更新render texture的内容
                mCamera->setPosition(xPos, yPos, zPos);
                mRenderTexture->update();

                String fileName = mPath + mSceneBaseName + Ogre::StringConverter::toString(i)
                    + "_" + Ogre::StringConverter::toString(j) + "." + mTexExtension;

                // 输出小纹理文件
                mRenderTexture->writeContentsToFile(fileName);

                mTempOutputFileNames.push_back(fileName);

                // 读取刚创建的纹理
                Ogre::Image* tempImage = new Ogre::Image;
                
                tempImage->load(mSceneBaseName + Ogre::StringConverter::toString(i)
                    + "_" + Ogre::StringConverter::toString(j) + "." + mTexExtension, TEMP_GROUP_NAME);

                // 获取render texture中的内容
                uchar* tempImageData = tempImage->getData();

                // 定位在mini map中的左上角
                uint miniMapIndex = ( j * mTexHeight * miniMapWidth + i * mTexWidth ) * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat);

                uchar* startData = miniMapData + miniMapIndex;

                for ( size_t height = 0; height < tempImage->getHeight(); ++height )
                {
                    for ( size_t width = 0; width < tempImage->getWidth(); ++width )
                    {
                        memcpy(startData, tempImageData, Ogre::PixelUtil::getNumElemBytes(mOutPutFormat));

                        startData += Ogre::PixelUtil::getNumElemBytes(mOutPutFormat);
                        tempImageData += Ogre::PixelUtil::getNumElemBytes( tempImage->getFormat() );
                    }
                    startData += (miniMapWidth - tempImage->getWidth()) * Ogre::PixelUtil::getNumElemBytes(mOutPutFormat);
                }

                delete tempImage;

                // 移动摄像机的z坐标
                if (mUseRealCameraAngle)
                {
                    zPos += (mInvertCameraDir * (projectSize)).z;
                    xPos += (mInvertCameraDir * (projectSize)).x;
                }
                else
                   zPos += mTileSize;
            }
            
            if (mUseRealCameraAngle)
            {
                xPos = originPoint.x;
                zPos = originPoint.z;

                xPos += (mMoveZDir * (mTileSize) * (i+1)).x;
                zPos += (mMoveZDir * (mTileSize) * (i+1)).z;
            }
            else
            {
                // 操作完每一列之后,重置摄像机的z坐标
                zPos = terrainData->mMinZ;

                // 移动摄像机的x坐标
                xPos += mTileSize;
            }
        } 

        // 保存mini map并输出
        Ogre::Image* miniMapImage = new Ogre::Image;
        miniMapImage->loadDynamicImage(miniMapData, miniMapWidth, miniMapHeight, 1, mOutPutFormat, true);

        miniMapImage->save(mPath + mOutFileName + "." + mTexExtension);

        delete miniMapImage;

        rgm.destroyResourceGroup(TEMP_GROUP_NAME);

        return true;
    }
Example #8
0
AssetLoadState TextureAsset::DeserializeFromData(const u8 *data, size_t numBytes)
{
    if (!data)
        return ASSET_LOAD_FAILED; ///\todo Log out error.
    if (numBytes == 0)
        return ASSET_LOAD_FAILED; ///\todo Log out error.

    // Don't load textures to memory in headless mode
    if (assetAPI->IsHeadless())
    {
	    return ASSET_LOAD_FAILED;
    }

    if (OGRE_THREAD_SUPPORT != 0)
    {
        // We can only do threaded loading from disk, and not any disk location but only from asset cache.
        // local:// refs will return empty string here and those will fall back to the non-threaded loading.
        // Do not change this to do DiskCache() as that directory for local:// refs will not be a known resource location for ogre.
        QString cacheDiskSource = assetAPI->GetAssetCache()->GetDiskSource(QUrl(Name()));
        if (!cacheDiskSource.isEmpty())
        {
            QFileInfo fileInfo(cacheDiskSource);
            std::string sanitatedAssetRef = fileInfo.fileName().toStdString();             
            loadTicket_ = Ogre::ResourceBackgroundQueue::getSingleton().load(Ogre::TextureManager::getSingleton().getResourceType(),
                                                                             sanitatedAssetRef, OgreRenderer::OgreRenderingModule::CACHE_RESOURCE_GROUP,
                                                                             false, 0, 0, this);
            return ASSET_LOAD_PROCESSING;
        }
    }                                                
    
    try
    {
        // Convert the data into Ogre's own DataStream format.
        std::vector<u8> tempData(data, data + numBytes);
#include "DisableMemoryLeakCheck.h"
        Ogre::DataStreamPtr stream(new Ogre::MemoryDataStream(&tempData[0], tempData.size(), false));
#include "EnableMemoryLeakCheck.h"
        // Load up the image as an Ogre CPU image object.
        Ogre::Image image;
        image.load(stream);

        if (ogreTexture.isNull()) // If we are creating this texture for the first time, create a new Ogre::Texture object.
        {
            ogreAssetName = OgreRenderer::SanitateAssetIdForOgre(this->Name().toStdString()).c_str();
            ogreTexture = Ogre::TextureManager::getSingleton().loadImage(ogreAssetName.toStdString(), Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, image);
        }
        else // If we're loading on top of an Ogre::Texture we've created before, don't lose the old Ogre::Texture object, but reuse the old.
        {    // This will allow all existing materials to keep referring to this texture, and they'll get the updated texture image immediately.
            ogreTexture->freeInternalResources(); 

            if (image.getWidth() != ogreTexture->getWidth() || image.getHeight() != ogreTexture->getHeight() || image.getFormat() != ogreTexture->getFormat())
            {
                ogreTexture->setWidth(image.getWidth());
                ogreTexture->setHeight(image.getHeight());
                ogreTexture->setFormat(image.getFormat());
            }

            if (ogreTexture->getBuffer().isNull())
            {
                LogError("DeserializeFromData: Failed to create texture " + this->Name().toStdString() + ": OgreTexture::getBuffer() was null!");
                return ASSET_LOAD_FAILED;
            }

            Ogre::PixelBox pixelBox(Ogre::Box(0,0, image.getWidth(), image.getHeight()), image.getFormat(), (void*)image.getData());
            ogreTexture->getBuffer()->blitFromMemory(pixelBox);

            ogreTexture->createInternalResources();
        }

        return ASSET_LOAD_SUCCESFULL;
    }
    catch (Ogre::Exception &e)
    {
        LogError("DeserializeFromData: Failed to create texture " + this->Name().toStdString() + ": " + std::string(e.what()));
        return ASSET_LOAD_FAILED;
    }
}
Example #9
0
void 
BrushSelector::buildPreviewBitmap( const Fairy::TextureInfo texInfo )
{
    const Ogre::uchar BytePerPixel = 8;

    // 读取原始image
    Ogre::Image *oriImage = GetSceneManipulator()->getPreviewImage(texInfo.ownerTextureName);
    // 源大纹理的大小
    size_t oriImageHeight = oriImage->getHeight();
    size_t oriImageWidth = oriImage->getWidth();

    Ogre::uchar *oriImageData = oriImage->getData();
    // 所选纹理的大小
    size_t newImageWidth = texInfo.width*TexTileSize;
    size_t newImageHeight = texInfo.height*TexTileSize;

    // 分配一个足够大的空间来保存新建的image的数据
    size_t newImagegetRowSpan = newImageWidth*oriImage->getBPP()/BytePerPixel;  // 新建的image的行宽(单位为字节)
    Ogre::uchar *newImageData = OGRE_ALLOC_T(Ogre::uchar, oriImageHeight*newImagegetRowSpan, Ogre::MEMCATEGORY_GENERAL);//new Ogre::uchar[newImageHeight*newImagegetRowSpan];
    
    Ogre::uchar *newImageDataPointer = newImageData;
    // 得知起始像素点
    size_t startPoint = ( oriImageWidth * texInfo.topCorner + texInfo.leftCorner )
        * TexTileSize * oriImage->getBPP()/BytePerPixel;

    Ogre::uchar *oriImagedataPointer = oriImageData + startPoint;

    // 把所选的纹理的数据提取出来,并创建一个新的image
    for ( Ogre::uint i=0; i<newImageHeight; ++i )
    {
        memcpy(newImageDataPointer, oriImagedataPointer, newImagegetRowSpan);
        newImageDataPointer += newImagegetRowSpan;
        oriImagedataPointer += oriImage->getRowSpan();
    }

    Ogre::Image newImage;
    newImage.loadDynamicImage(newImageData,newImageWidth,newImageHeight,1,oriImage->getFormat(),true);

    // 如果所选纹理大于64*64,就先resize
    if ( texInfo.width > 1 || texInfo.height > 1 )
        newImage.resize(mPreviewImageWidth, mPreviewImageHeight);

    // 如果有alpha,要与黑白图进行混合
    if ( newImage.getHasAlpha() )
    {  
		Ogre::ColourValue col;

		for ( int i=0; i<mPreviewImageWidth; ++i )
		{
			for ( int j=0; j<mPreviewImageWidth; ++j )
			{
				col = newImage.getColourAt(j,i,0);

				float alphaValue = col.a;

				unsigned char r = col.r*255 * alphaValue + mBlackWhitePreviewImage.GetRed(i,j) * ( 1.0f - alphaValue);
				unsigned char g = col.g*255 * alphaValue + mBlackWhitePreviewImage.GetGreen(i,j) * ( 1.0f - alphaValue);
				unsigned char b = col.b*255 * alphaValue + mBlackWhitePreviewImage.GetBlue(i,j) * ( 1.0f - alphaValue);

				// 设置到image中
				mCurrentPreviewImage.SetRGB(j,i,r,g,b);
			}
		}
        // 设置到缩略图控件中
        mBrushesPreview->SetBitmap(mCurrentPreviewImage);
    }
    // 没有alpha,就直接拷贝数据
    else
    {
		Ogre::ColourValue col;

		for ( int i=0; i<mPreviewImageWidth; ++i )
		{
			for ( int j=0; j<mPreviewImageWidth; ++j )
			{
				col = newImage.getColourAt(j,i,0);

				unsigned char r = col.r*255;
				unsigned char g = col.g*255;
				unsigned char b = col.b*255;

				// 设置到image中
				mCurrentPreviewImage.SetRGB(j,i,r,g,b);
			}
		}

        mBrushesPreview->SetBitmap(mCurrentPreviewImage);    
    }
}
void 
MaterialPreviewDialog::buildPreviewBitmap( const Ogre::String &texName )
{
	const Ogre::uchar BytePerPixel = 8;

	// 读取原始image
	Ogre::Image *oriImage = getPreviewImage(texName);
	// 源大纹理的大小
	size_t oriImageHeight = oriImage->getHeight();
	size_t oriImageWidth = oriImage->getWidth();

	Ogre::uchar *oriImageData = oriImage->getData();

	// 分配一个足够大的空间来保存新建的image的数据
	size_t newImagegetRowSpan = oriImageWidth*oriImage->getBPP()/BytePerPixel;  // 新建的image的行宽(单位为字节)
	Ogre::uchar *newImageData = new Ogre::uchar[oriImageHeight*newImagegetRowSpan];

	Ogre::uchar *newImageDataPointer = newImageData;

	Ogre::uchar *oriImagedataPointer = oriImageData;

	// 把所选的纹理的数据提取出来,并创建一个新的image
	for ( Ogre::uint i=0; i<oriImageHeight; ++i )
	{
		memcpy(newImageDataPointer, oriImagedataPointer, newImagegetRowSpan);
		newImageDataPointer += newImagegetRowSpan;
		oriImagedataPointer += oriImage->getRowSpan();
	}

	Ogre::Image newImage;
	newImage.loadDynamicImage(newImageData,oriImageWidth,oriImageHeight,1,oriImage->getFormat(),true);

	// 如果所选纹理大于64*64,就先resize
	if ( oriImageWidth > mPreviewImageWidth || oriImageHeight > mPreviewImageHeight )
		newImage.resize(mPreviewImageWidth, mPreviewImageHeight);

	// 如果有alpha,要与黑白图进行混合
	if ( newImage.getHasAlpha() )
	{
		Ogre::uchar *tempPtr = newImage.getData();

		assert (tempPtr);

		for ( size_t i=0; i<mPreviewImageHeight; ++i )
			for ( size_t j=0; j<mPreviewImageWidth; ++j )
			{
				// 取出alpha值
				float alphaValue = (float)tempPtr[3] / 255.0f;

				// 计算出经过alpha混合后的颜色值
				unsigned char r = tempPtr[2] * alphaValue;
				unsigned char g = tempPtr[1] * alphaValue;
				unsigned char b = tempPtr[0] * alphaValue;

				// 设置到image中
				mCurrentPreviewImage.SetRGB(j,i,r,g,b);
				tempPtr += 4;
			}

			// 要把指针移回到图片数据的
			tempPtr -= mPreviewImageHeight * mPreviewImageWidth * 4;
			// 设置到缩略图控件中
	}
	// 没有alpha,就直接拷贝数据
	else
	{
		memcpy ( mCurrentPreviewImage.GetData(), newImage.getData(), newImage.getSize() );
	}
}
void 
MaterialPreviewDialog::buildPreviewBitmap( const Ogre::String &texName )
{
	const Ogre::uchar BytePerPixel = 8;

	// 读取原始image
	Ogre::Image *oriImage = getPreviewImage(texName);
	// 源大纹理的大小
	size_t oriImageHeight = oriImage->getHeight();
	size_t oriImageWidth = oriImage->getWidth();

	Ogre::uchar *oriImageData = oriImage->getData();

	// 分配一个足够大的空间来保存新建的image的数据
	size_t newImagegetRowSpan = oriImageWidth*oriImage->getBPP()/BytePerPixel;  // 新建的image的行宽(单位为字节)
	Ogre::uchar *newImageData = OGRE_ALLOC_T(Ogre::uchar, oriImageHeight*newImagegetRowSpan, Ogre::MEMCATEGORY_GENERAL);//new Ogre::uchar[oriImageHeight*newImagegetRowSpan];

	Ogre::uchar *newImageDataPointer = newImageData;

	Ogre::uchar *oriImagedataPointer = oriImageData;

	// 把所选的纹理的数据提取出来,并创建一个新的image
	for ( Ogre::uint i=0; i<oriImageHeight; ++i )
	{
		memcpy(newImageDataPointer, oriImagedataPointer, newImagegetRowSpan);
		newImageDataPointer += newImagegetRowSpan;
		oriImagedataPointer += oriImage->getRowSpan();
	}

	Ogre::Image newImage;
	newImage.loadDynamicImage(newImageData,oriImageWidth,oriImageHeight,1,oriImage->getFormat(),true);

	// 如果所选纹理大于64*64,就先resize
	if ( oriImageWidth > mPreviewImageWidth || oriImageHeight > mPreviewImageHeight )
		newImage.resize(mPreviewImageWidth, mPreviewImageHeight);

	// 如果有alpha,要与黑白图进行混合
	if ( newImage.getHasAlpha() )
	{
		Ogre::ColourValue col;

		for ( int i=0; i<mPreviewImageWidth; ++i )
		{
			for ( int j=0; j<mPreviewImageWidth; ++j )
			{
				col = newImage.getColourAt(j,i,0);

				float alphaValue = col.a;

				unsigned char r = col.r*255 * alphaValue; 
				unsigned char g = col.g*255 * alphaValue; 
				unsigned char b = col.b*255 * alphaValue;

				// 设置到image中
				mCurrentPreviewImage.SetRGB(j,i,r,g,b);
			}
		}
	}
	// 没有alpha,就直接拷贝数据
	else
	{
		Ogre::ColourValue col;

		for ( int i=0; i<mPreviewImageWidth; ++i )
		{
			for ( int j=0; j<mPreviewImageWidth; ++j )
			{
				col = newImage.getColourAt(j,i,0);

				unsigned char r = col.r*255;
				unsigned char g = col.g*255;
				unsigned char b = col.b*255;

				// 设置到image中
				mCurrentPreviewImage.SetRGB(j,i,r,g,b);
			}
		}
	}
}
    // ----------------------------------------------------------------------
    void FontSerializer::exportFont(const Font *pFont, const Ogre::String &fileName)
    {
        // Open/create the file
		mpfFile = fopen(fileName.c_str(), "wb");
		if (!mpfFile)
		{
		    // Throw an error if the file was not found, or was not possible to read
		    SONETTO_THROW("A file was not found!");
		}
		fwrite(&Font::mFourCC, sizeof(uint32), 1, mpfFile);

		fwrite(&pFont->mVersion, sizeof(uint32), 1, mpfFile);
		fwrite(&pFont->mEncode, sizeof(uint32), 1, mpfFile);
		fwrite(&pFont->mVerticalOffsetTop, sizeof(float), 1, mpfFile);
		fwrite(&pFont->mVerticalOffsetBottom, sizeof(float), 1, mpfFile);
		fwrite(&pFont->mHorizontalScale, sizeof(float), 1, mpfFile);

		saveString(pFont->mIName);

		if(pFont->mMaterial.isNull())
            SONETTO_THROW("Material does not exist");

		Ogre::Pass * pass = pFont->mMaterial->getTechnique(0)->getPass(0);

		bool has_separate_blend = pass->hasSeparateSceneBlending();

        uint32 mat_scene_blend_source = (uint32)pass->getSourceBlendFactor();
        uint32 mat_scene_blend_dest = (uint32)pass->getDestBlendFactor();
        uint32 mat_scene_blend_source_a = (uint32)pass->getSourceBlendFactorAlpha();
        uint32 mat_scene_blend_dest_a = (uint32)pass->getDestBlendFactorAlpha();

        fwrite(&has_separate_blend, sizeof(bool), 1, mpfFile);
        fwrite(&mat_scene_blend_source, sizeof(uint32), 1, mpfFile);
        fwrite(&mat_scene_blend_dest, sizeof(uint32), 1, mpfFile);
        fwrite(&mat_scene_blend_source_a, sizeof(uint32), 1, mpfFile);
        fwrite(&mat_scene_blend_dest_a, sizeof(uint32), 1, mpfFile);

        uint32 mat_alpha_reject_func = (uint32)pass->getAlphaRejectFunction();
        uint8 mat_alpha_reject_val = (uint8)pass->getAlphaRejectValue();
        bool map_alpha_reject_atc = pass->isAlphaToCoverageEnabled();

        fwrite(&mat_alpha_reject_func, sizeof(uint32), 1, mpfFile);
        fwrite(&mat_alpha_reject_val, sizeof(uint8), 1, mpfFile);
        fwrite(&map_alpha_reject_atc, sizeof(bool), 1, mpfFile);

        Ogre::TextureUnitState * texunit = pass->getTextureUnitState(0);

        Ogre::TextureUnitState::UVWAddressingMode tex_address_mode_uvw = texunit->getTextureAddressingMode();

        uint32 tex_address_mode_u = (uint32)tex_address_mode_uvw.u;
        uint32 tex_address_mode_v = (uint32)tex_address_mode_uvw.v;
        uint32 tex_address_mode_w = (uint32)tex_address_mode_uvw.w;

        uint32 tex_filtering_min = (uint32)texunit->getTextureFiltering(Ogre::FT_MIN);
        uint32 tex_filtering_mag = (uint32)texunit->getTextureFiltering(Ogre::FT_MAG);
        Ogre::ColourValue tex_border_color = texunit->getTextureBorderColour();

        fwrite(&tex_address_mode_u,sizeof(uint32), 1, mpfFile);
        fwrite(&tex_address_mode_v,sizeof(uint32), 1, mpfFile);
        fwrite(&tex_address_mode_w,sizeof(uint32), 1, mpfFile);
        fwrite(&tex_filtering_min,sizeof(uint32), 1, mpfFile);
        fwrite(&tex_filtering_mag,sizeof(uint32), 1, mpfFile);
        fwrite(tex_border_color.ptr(),sizeof(float)*4, 1, mpfFile);

        uint32 colsize = (uint32)pFont->mColorList.size();
        fwrite(&colsize,sizeof(uint32), 1, mpfFile);

        for(uint32 i = 0; i != colsize; ++i)
        {
            fwrite(pFont->mColorList[i].ptr(),sizeof(float)*4, 1, mpfFile);
        }

        for(uint32 i = 0; i != 256; ++i)
        {
            FontGlyph glyph = pFont->mGlyph[i];
            fwrite(&glyph, sizeof(FontGlyph), 1,mpfFile);
        }

        Ogre::Image * tex = pFont->mFontImage;

        size_t uWidth = tex->getWidth();
        size_t uHeight = tex->getHeight();
        size_t uDepth = tex->getDepth();
		size_t eFormat = (uint32)tex->getFormat();
		size_t numFaces = tex->getNumFaces();
		size_t numMipMaps = tex->getNumMipmaps();

		fwrite(&uWidth, sizeof(size_t), 1, mpfFile);
		fwrite(&uHeight, sizeof(size_t), 1, mpfFile);
		fwrite(&uDepth, sizeof(size_t), 1, mpfFile);
		fwrite(&eFormat, sizeof(size_t), 1, mpfFile);
		fwrite(&numFaces, sizeof(size_t), 1, mpfFile);
		fwrite(&numMipMaps, sizeof(size_t), 1, mpfFile);

		size_t texdatasize = Ogre::Image::calculateSize(numMipMaps,
                                                        numFaces,
                                                        uWidth,
                                                        uHeight,
                                                        uDepth,
                                                        (Ogre::PixelFormat)eFormat);

		fwrite(tex->getData(),texdatasize, 1,mpfFile);
    }
/* ----------------------------------------------------------------------- 
 | build bullet height field shape and generate ogre mesh from grayscale image
 | 
 | @param in : 
 | @param out: raw data of height field terrain
 | ToDo: adjest grid scale, grid height, local scale, max/min height
   ----------------------------------------------------------------------- */
bool
buildHeightFieldTerrainFromImage(const Ogre::String& filename, 
                                 btDynamicsWorld* dynamicsWorld, 
                                 btAlignedObjectArray<btCollisionShape*>& collisionShapes,
                                 void* &data)
{
    Ogre::Image img;
    try
    {
        img.load(filename, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
    }   
    catch(Ogre::Exception err)
    {
        LOG(err.what());
        return false;
    }
    
    size_t grid_w = 65, grid_h = 65; // must be (2^N) + 1
    size_t grid_max_w = 129, grid_max_h = 129; // must be (2^N) + 1
    size_t img_w = img.getWidth();
    size_t img_h = img.getHeight();
    
    // validate image size is (2^N) + 1
    if ((img_w-1) & (img_w-2)) img_w = grid_w; 
    if ((img_h-1) & (img_h-2)) img_h = grid_h;
    //if (img_w > grid_max_w) img_w = grid_max_w; 
    //if (img_h > grid_max_h) img_h = grid_max_h; 

    LOG("LoadImage name=%s, width=%d, height=%d, width^2+1=%d, height^2+1=%d",
        filename.c_str(), img.getWidth(), img.getHeight(), img_w, img_h);
    img.resize(img_w, img_h);

    size_t pixelSize = Ogre::PixelUtil::getNumElemBytes(img.getFormat());    
    size_t bufSize = img.getSize() / pixelSize;
    data = new Ogre::Real[ bufSize ];
    Ogre::Real* dest = static_cast<Ogre::Real*>(data);
    memset(dest, 0, bufSize);
        
    /*
     | @ Notice the alignment problem
     | - uchar to float alignment
     | - pixel format in bytes as rawdata type, also affects alignment
     */
    Ogre::uchar* src = img.getData();    
    for (size_t i=0;i<bufSize;++i)
    {        
        dest[i] = ((Ogre::Real)src[i * pixelSize] - 127.0f)/16.0f;
    }
          
    // parameter    
    int upAxis = 1;
    btScalar gridSpacing = 5.0f;
    btScalar gridHeightScale = 0.2f;
    btScalar minHeight = -10.0f;
    btScalar maxHeight = 10.0f;
    btScalar defaultContactProcessingThreshold = BT_LARGE_FLOAT;

	btHeightfieldTerrainShape *heightfieldShape =  
        new btHeightfieldTerrainShape(img_w, img_h,
                                      dest,
                                      gridHeightScale,
                                      minHeight, maxHeight,
                                      upAxis, PHY_FLOAT, false);
	btAssert(heightfieldShape && "null heightfield");

	// shape
	btVector3 localScaling(1.0f, 1.0f, 1.0f);
	heightfieldShape->setLocalScaling(localScaling);    
    collisionShapes.push_back(heightfieldShape);

    // rigidBody
    btDefaultMotionState* motionState = new btDefaultMotionState(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)));
    btRigidBody::btRigidBodyConstructionInfo cInfo(0, motionState, heightfieldShape, btVector3(0,0,0));
    btRigidBody* rigidBody = new btRigidBody(cInfo);        	
	rigidBody->setContactProcessingThreshold(defaultContactProcessingThreshold);
    int flags = rigidBody->getCollisionFlags();
    rigidBody->setCollisionFlags(flags | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT);
    
    dynamicsWorld->addRigidBody(rigidBody);
    
    // add ogre height field mesh
    Ogre::SceneManager* sceneMgr = Ogre::Root::getSingletonPtr()->getSceneManager("DefaultSceneManager");
    btAssert(sceneMgr);
    
    Ogre::ManualObject* obj = sceneMgr->createManualObject("btHeightFieldEntity");

    btVector3 aabbMin, aabbMax;
    heightfieldShape->getAabb(btTransform(btQuaternion(0,0,0,1),btVector3(0,0,0)), aabbMin, aabbMax);

    btHeightFieldProcessor callback(obj, "DefaultPlane");
    heightfieldShape->processAllTriangles(&callback, aabbMin, aabbMax);
   
    sceneMgr->getRootSceneNode()->attachObject(obj);

    return true;
}