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;
    }
Exemple #2
0
 BoundingBox<real> getOgreWorldBoundingBox() const {
     return mOgreObject ? fromOgre<real>(mOgreObject->getWorldBoundingBox()) : BoundingBox<real>::null();
 }