Logo Search packages:      
Sourcecode: ogre version File versions

OgreManualObject.cpp

/*
-----------------------------------------------------------------------------
This source file is part of OGRE
    (Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2006 Torus Knot Software Ltd
Also see acknowledgements in Readme.html

This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA, or go to
http://www.gnu.org/copyleft/lesser.txt.

You may alternatively use this source under the terms of a specific version of
the OGRE Unrestricted License provided you have obtained such a license from
Torus Knot Software Ltd.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreManualObject.h"
#include "OgreException.h"
#include "OgreMaterialManager.h"
#include "OgreSceneNode.h"
#include "OgreRoot.h"
#include "OgreRenderSystem.h"
#include "OgreHardwareBufferManager.h"
#include "OgreEdgeListBuilder.h"
#include "OgreMeshManager.h"
#include "OgreMesh.h"
#include "OgreSubMesh.h"

namespace Ogre {

#define TEMP_INITIAL_SIZE 50
#define TEMP_VERTEXSIZE_GUESS sizeof(float) * 12
#define TEMP_INITIAL_VERTEX_SIZE TEMP_VERTEXSIZE_GUESS * TEMP_INITIAL_SIZE
#define TEMP_INITIAL_INDEX_SIZE sizeof(uint16) * TEMP_INITIAL_SIZE
      //-----------------------------------------------------------------------------
      ManualObject::ManualObject(const String& name)
            : MovableObject(name),
              mDynamic(false), mCurrentSection(0), mFirstVertex(true),
              mTempVertexPending(false),
              mTempVertexBuffer(0), mTempVertexSize(TEMP_INITIAL_VERTEX_SIZE),
              mTempIndexBuffer(0), mTempIndexSize(TEMP_INITIAL_INDEX_SIZE),
              mDeclSize(0), mEstVertexCount(0), mEstIndexCount(0), mTexCoordIndex(0), 
              mRadius(0), mAnyIndexed(false), mEdgeList(0), 
              mUseIdentityProjection(false), mUseIdentityView(false)
      {
      }
      //-----------------------------------------------------------------------------
      ManualObject::~ManualObject()
      {
            clear();
      }
      //-----------------------------------------------------------------------------
00066       void ManualObject::clear(void)
      {
            resetTempAreas();
            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  delete *i;
            }
            mSectionList.clear();
            mRadius = 0;
            mAABB.setNull();
            delete mEdgeList;
            mEdgeList = 0;
            mAnyIndexed = false;
            for (ShadowRenderableList::iterator s = mShadowRenderables.begin();
                  s != mShadowRenderables.end(); ++s)
            {
                  delete *s;
            }
            mShadowRenderables.clear();


      }
      //-----------------------------------------------------------------------------
00089       void ManualObject::resetTempAreas(void)
      {
            delete [] mTempVertexBuffer;
            delete [] mTempIndexBuffer;
            mTempVertexBuffer = 0;
            mTempIndexBuffer = 0;
            mTempVertexSize = TEMP_INITIAL_VERTEX_SIZE;
            mTempIndexSize = TEMP_INITIAL_INDEX_SIZE;
      }
      //-----------------------------------------------------------------------------
00099       void ManualObject::resizeTempVertexBufferIfNeeded(size_t numVerts)
      {
            // Calculate byte size
            // Use decl if we know it by now, otherwise default size to pos/norm/texcoord*2
            size_t newSize;
            if (!mFirstVertex)
            {
                  newSize = mDeclSize * numVerts;
            }
            else
            {
                  // estimate - size checks will deal for subsequent verts
                  newSize = TEMP_VERTEXSIZE_GUESS * numVerts;
            }
            if (newSize > mTempVertexSize || !mTempVertexBuffer)
            {
                  if (!mTempVertexBuffer)
                  {
                        // init
                        newSize = mTempVertexSize;
                  }
                  else
                  {
                        // increase to at least double current
                        newSize = std::max(newSize, mTempVertexSize*2);
                  }
                  // copy old data
                  char* tmp = mTempVertexBuffer;
                  mTempVertexBuffer = new char[newSize];
                  if (tmp)
                  {
                        memcpy(mTempVertexBuffer, tmp, mTempVertexSize);
                        // delete old buffer
                        delete [] tmp;
                  }
                  mTempVertexSize = newSize;
            }
      }
      //-----------------------------------------------------------------------------
00138       void ManualObject::resizeTempIndexBufferIfNeeded(size_t numInds)
      {
            size_t newSize = numInds * sizeof(uint16);
            if (newSize > mTempIndexSize || !mTempIndexBuffer)
            {
                  if (!mTempIndexBuffer)
                  {
                        // init
                        newSize = mTempIndexSize;
                  }
                  else
                  {
                        // increase to at least double current
                        newSize = std::max(newSize, mTempIndexSize*2);
                  }
                  numInds = newSize / sizeof(uint16);
                  uint16* tmp = mTempIndexBuffer;
                  mTempIndexBuffer = new uint16[numInds];
                  if (tmp)
                  {
                        memcpy(mTempIndexBuffer, tmp, mTempIndexSize);
                        delete [] tmp;
                  }
                  mTempIndexSize = newSize;
            }

      }
      //-----------------------------------------------------------------------------
00166       void ManualObject::estimateVertexCount(size_t vcount)
      {
            resizeTempVertexBufferIfNeeded(vcount);
            mEstVertexCount = vcount;
      }
      //-----------------------------------------------------------------------------
00172       void ManualObject::estimateIndexCount(size_t icount)
      {
            resizeTempIndexBufferIfNeeded(icount);
            mEstIndexCount = icount;
      }
      //-----------------------------------------------------------------------------
00178       void ManualObject::begin(const String& materialName,
            RenderOperation::OperationType opType)
      {
            if (mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You cannot call begin() again until after you call end()",
                        "ManualObject::begin");
            }
            mCurrentSection = new ManualObjectSection(this, materialName, opType);
            mCurrentUpdating = false;
            mCurrentSection->setUseIdentityProjection(mUseIdentityProjection);
            mCurrentSection->setUseIdentityView(mUseIdentityView);
            mSectionList.push_back(mCurrentSection);
            mFirstVertex = true;
            mDeclSize = 0;
            mTexCoordIndex = 0;
      }
      //-----------------------------------------------------------------------------
00197       void ManualObject::beginUpdate(size_t sectionIndex)
      {
            if (mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You cannot call begin() again until after you call end()",
                        "ManualObject::beginUpdate");
            }
            if (sectionIndex >= mSectionList.size())
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Invalid section index - out of range.",
                        "ManualObject::beginUpdate");
            }
            mCurrentSection = mSectionList[sectionIndex];
            mCurrentUpdating = true;
            mFirstVertex = true;
            mTexCoordIndex = 0;
            // reset vertex & index count
            RenderOperation* rop = mCurrentSection->getRenderOperation();
            rop->vertexData->vertexCount = 0;
            if (rop->indexData)
                  rop->indexData->indexCount = 0;
            rop->useIndexes = false;
            mDeclSize = rop->vertexData->vertexDeclaration->getVertexSize(0);
      }
      //-----------------------------------------------------------------------------
00224       void ManualObject::position(const Vector3& pos)
      {
            position(pos.x, pos.y, pos.z);
      }
      //-----------------------------------------------------------------------------
00229       void ManualObject::position(Real x, Real y, Real z)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::position");
            }
            if (mTempVertexPending)
            {
                  // bake current vertex
                  copyTempVertexToBuffer();
                  mFirstVertex = false;
            }

            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_FLOAT3, VES_POSITION);
                  mDeclSize += VertexElement::getTypeSize(VET_FLOAT3);
            }

            mTempVertex.position.x = x;
            mTempVertex.position.y = y;
            mTempVertex.position.z = z;

            // update bounds
            mAABB.merge(mTempVertex.position);
            mRadius = std::max(mRadius, mTempVertex.position.length());

            // reset current texture coord
            mTexCoordIndex = 0;

            mTempVertexPending = true;
      }
      //-----------------------------------------------------------------------------
00266       void ManualObject::normal(const Vector3& norm)
      {
            normal(norm.x, norm.y, norm.z);
      }
      //-----------------------------------------------------------------------------
00271       void ManualObject::normal(Real x, Real y, Real z)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::normal");
            }
            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_FLOAT3, VES_NORMAL);
                  mDeclSize += VertexElement::getTypeSize(VET_FLOAT3);
            }
            mTempVertex.normal.x = x;
            mTempVertex.normal.y = y;
            mTempVertex.normal.z = z;
      }
      //-----------------------------------------------------------------------------
00291       void ManualObject::textureCoord(Real u)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::textureCoord");
            }
            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_FLOAT1, VES_TEXTURE_COORDINATES, mTexCoordIndex);
                  mDeclSize += VertexElement::getTypeSize(VET_FLOAT1);
            }
            mTempVertex.texCoordDims[mTexCoordIndex] = 1;
            mTempVertex.texCoord[mTexCoordIndex].x = u;

            ++mTexCoordIndex;

      }
      //-----------------------------------------------------------------------------
00313       void ManualObject::textureCoord(Real u, Real v)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::textureCoord");
            }
            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_FLOAT2, VES_TEXTURE_COORDINATES, mTexCoordIndex);
                  mDeclSize += VertexElement::getTypeSize(VET_FLOAT2);
            }
            mTempVertex.texCoordDims[mTexCoordIndex] = 2;
            mTempVertex.texCoord[mTexCoordIndex].x = u;
            mTempVertex.texCoord[mTexCoordIndex].y = v;

            ++mTexCoordIndex;
      }
      //-----------------------------------------------------------------------------
00335       void ManualObject::textureCoord(Real u, Real v, Real w)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::textureCoord");
            }
            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_FLOAT3, VES_TEXTURE_COORDINATES, mTexCoordIndex);
                  mDeclSize += VertexElement::getTypeSize(VET_FLOAT3);
            }
            mTempVertex.texCoordDims[mTexCoordIndex] = 3;
            mTempVertex.texCoord[mTexCoordIndex].x = u;
            mTempVertex.texCoord[mTexCoordIndex].y = v;
            mTempVertex.texCoord[mTexCoordIndex].z = w;

            ++mTexCoordIndex;
      }
      //-----------------------------------------------------------------------------
00358       void ManualObject::textureCoord(const Vector2& uv)
      {
            textureCoord(uv.x, uv.y);
      }
      //-----------------------------------------------------------------------------
00363       void ManualObject::textureCoord(const Vector3& uvw)
      {
            textureCoord(uvw.x, uvw.y, uvw.z);
      }
      //-----------------------------------------------------------------------------
00368       void ManualObject::colour(const ColourValue& col)
      {
            colour(col.r, col.g, col.b, col.a);
      }
      //-----------------------------------------------------------------------------
00373       void ManualObject::colour(Real r, Real g, Real b, Real a)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::colour");
            }
            if (mFirstVertex && !mCurrentUpdating)
            {
                  // defining declaration
                  mCurrentSection->getRenderOperation()->vertexData->vertexDeclaration
                        ->addElement(0, mDeclSize, VET_COLOUR, VES_DIFFUSE);
                  mDeclSize += VertexElement::getTypeSize(VET_COLOUR);
            }
            mTempVertex.colour.r = r;
            mTempVertex.colour.g = g;
            mTempVertex.colour.b = b;
            mTempVertex.colour.a = a;

      }
      //-----------------------------------------------------------------------------
00395       void ManualObject::index(uint16 idx)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::index");
            }
            mAnyIndexed = true;
            // make sure we have index data
            RenderOperation* rop = mCurrentSection->getRenderOperation();
            if (!rop->indexData)
            {
                  rop->indexData = new IndexData();
                  rop->indexData->indexCount = 0;
            }
            rop->useIndexes = true;
            resizeTempIndexBufferIfNeeded(++rop->indexData->indexCount);

            mTempIndexBuffer[rop->indexData->indexCount - 1] = idx;
      }
      //-----------------------------------------------------------------------------
00417       void ManualObject::triangle(uint16 i1, uint16 i2, uint16 i3)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You must call begin() before this method",
                        "ManualObject::index");
            }
            if (mCurrentSection->getRenderOperation()->operationType !=
                  RenderOperation::OT_TRIANGLE_LIST)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "This method is only valid on triangle lists",
                        "ManualObject::index");
            }

            index(i1);
            index(i2);
            index(i3);
      }
      //-----------------------------------------------------------------------------
00438       void ManualObject::quad(uint16 i1, uint16 i2, uint16 i3, uint16 i4)
      {
            // first tri
            triangle(i1, i2, i3);
            // second tri
            triangle(i3, i4, i1);
      }
      //-----------------------------------------------------------------------------
00446       void ManualObject::copyTempVertexToBuffer(void)
      {
            mTempVertexPending = false;
            RenderOperation* rop = mCurrentSection->getRenderOperation();
            if (rop->vertexData->vertexCount == 0 && !mCurrentUpdating)
            {
                  // first vertex, autoorganise decl
                  VertexDeclaration* oldDcl = rop->vertexData->vertexDeclaration;
                  rop->vertexData->vertexDeclaration =
                        oldDcl->getAutoOrganisedDeclaration(false, false);
                  HardwareBufferManager::getSingleton().destroyVertexDeclaration(oldDcl);
            }
            resizeTempVertexBufferIfNeeded(++rop->vertexData->vertexCount);

            // get base pointer
            char* pBase = mTempVertexBuffer + (mDeclSize * (rop->vertexData->vertexCount-1));
            const VertexDeclaration::VertexElementList& elemList =
                  rop->vertexData->vertexDeclaration->getElements();
            for (VertexDeclaration::VertexElementList::const_iterator i = elemList.begin();
                  i != elemList.end(); ++i)
            {
                  float* pFloat = 0;
                  RGBA* pRGBA = 0;
                  const VertexElement& elem = *i;
                  switch(elem.getType())
                  {
                  case VET_FLOAT1:
                  case VET_FLOAT2:
                  case VET_FLOAT3:
                        elem.baseVertexPointerToElement(pBase, &pFloat);
                        break;
                  case VET_COLOUR:
                  case VET_COLOUR_ABGR:
                  case VET_COLOUR_ARGB:
                        elem.baseVertexPointerToElement(pBase, &pRGBA);
                        break;
                  default:
                        // nop ?
                        break;
                  };


                  RenderSystem* rs;
                  unsigned short dims;
                  switch(elem.getSemantic())
                  {
                  case VES_POSITION:
                        *pFloat++ = mTempVertex.position.x;
                        *pFloat++ = mTempVertex.position.y;
                        *pFloat++ = mTempVertex.position.z;
                        break;
                  case VES_NORMAL:
                        *pFloat++ = mTempVertex.normal.x;
                        *pFloat++ = mTempVertex.normal.y;
                        *pFloat++ = mTempVertex.normal.z;
                        break;
                  case VES_TEXTURE_COORDINATES:
                        dims = VertexElement::getTypeCount(elem.getType());
                        for (ushort t = 0; t < dims; ++t)
                              *pFloat++ = mTempVertex.texCoord[elem.getIndex()][t];
                        break;
                  case VES_DIFFUSE:
                        rs = Root::getSingleton().getRenderSystem();
                        if (rs)
                              rs->convertColourValue(mTempVertex.colour, pRGBA++);
                        else
                              *pRGBA++ = mTempVertex.colour.getAsRGBA(); // pick one!
                        break;
                  default:
                        // nop ?
                        break;
                  };

            }

      }
      //-----------------------------------------------------------------------------
00523       ManualObject::ManualObjectSection* ManualObject::end(void)
      {
            if (!mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You cannot call end() until after you call begin()",
                        "ManualObject::end");
            }
            if (mTempVertexPending)
            {
                  // bake current vertex
                  copyTempVertexToBuffer();
            }

            // pointer that will be returned
            ManualObjectSection* result = NULL;

            RenderOperation* rop = mCurrentSection->getRenderOperation();
            // Check for empty content
            if (rop->vertexData->vertexCount == 0 ||
                  (rop->useIndexes && rop->indexData->indexCount == 0))
            {
                  // You're wasting my time sonny
                  if (mCurrentUpdating)
                  {
                        // Can't just undo / remove since may be in the middle
                        // Just allow counts to be 0, will not be issued to renderer

                        // return the finished section (though it has zero vertices)
                        result = mCurrentSection;
                  }
                  else
                  {
                        // First creation, can really undo
                        // Has already been added to section list end, so remove
                        mSectionList.pop_back();
                        delete mCurrentSection;

                  }
            }
            else // not an empty section
            {

                  // Bake the real buffers
                  HardwareVertexBufferSharedPtr vbuf;
                  // Check buffer sizes
                  bool vbufNeedsCreating = true;
                  bool ibufNeedsCreating = rop->useIndexes;
                  if (mCurrentUpdating)
                  {
                        // May be able to reuse buffers, check sizes
                        vbuf = rop->vertexData->vertexBufferBinding->getBuffer(0);
                        if (vbuf->getNumVertices() >= rop->vertexData->vertexCount)
                              vbufNeedsCreating = false;

                        if (rop->useIndexes)
                        {
                              if (rop->indexData->indexBuffer->getNumIndexes() >= 
                                    rop->indexData->indexCount)
                                    ibufNeedsCreating = false;
                        }

                  }
                  if (vbufNeedsCreating)
                  {
                        // Make the vertex buffer larger if estimated vertex count higher
                        // to allow for user-configured growth area
                        size_t vertexCount = std::max(rop->vertexData->vertexCount, 
                              mEstVertexCount);
                        vbuf =
                              HardwareBufferManager::getSingleton().createVertexBuffer(
                                    mDeclSize,
                                    vertexCount,
                                    mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : 
                                          HardwareBuffer::HBU_STATIC_WRITE_ONLY);
                        rop->vertexData->vertexBufferBinding->setBinding(0, vbuf);
                  }
                  if (ibufNeedsCreating)
                  {
                        // Make the index buffer larger if estimated index count higher
                        // to allow for user-configured growth area
                        size_t indexCount = std::max(rop->indexData->indexCount, 
                              mEstIndexCount);
                        rop->indexData->indexBuffer =
                              HardwareBufferManager::getSingleton().createIndexBuffer(
                                    HardwareIndexBuffer::IT_16BIT,
                                    indexCount,
                                    mDynamic? HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY : 
                                          HardwareBuffer::HBU_STATIC_WRITE_ONLY);
                  }
                  // Write vertex data
                  vbuf->writeData(
                        0, rop->vertexData->vertexCount * vbuf->getVertexSize(), 
                        mTempVertexBuffer, true);
                  // Write index data
                  if(rop->useIndexes)
                  {
                        rop->indexData->indexBuffer->writeData(
                              0, 
                              rop->indexData->indexCount 
                                    * rop->indexData->indexBuffer->getIndexSize(),
                              mTempIndexBuffer, true);
                  }

                  // return the finished section
                  result = mCurrentSection;

            } // empty section check

            mCurrentSection = 0;
            resetTempAreas();

            // Tell parent if present
            if (mParentNode)
            {
                  mParentNode->needUpdate();
            }

            // will return the finished section or NULL if
            // the section was empty (i.e. zero vertices/indices)
            return result;
      }
      //-----------------------------------------------------------------------------
00646       void ManualObject::setMaterialName(size_t idx, const String& name)
      {
            if (idx >= mSectionList.size())
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "Index out of bounds!",
                        "ManualObject::setMaterialName");
            }

            mSectionList[idx]->setMaterialName(name);

      }
      //-----------------------------------------------------------------------------
00659       MeshPtr ManualObject::convertToMesh(const String& meshName, const String& groupName)
      {
            if (mCurrentSection)
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "You cannot call convertToMesh() whilst you are in the middle of "
                        "defining the object; call end() first.",
                        "ManualObject::convertToMesh");
            }
            if (mSectionList.empty())
            {
                  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                        "No data defined to convert to a mesh.",
                        "ManualObject::convertToMesh");
            }
            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  ManualObjectSection* sec = *i;
                  if (!sec->getRenderOperation()->useIndexes)
                  {
                        OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
                              "Only indexed geometry may be converted to a mesh.",
                              "ManualObject::convertToMesh");
                  }
            }
            MeshPtr m = MeshManager::getSingleton().createManual(meshName, groupName);

            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  ManualObjectSection* sec = *i;
                  RenderOperation* rop = sec->getRenderOperation();
                  SubMesh* sm = m->createSubMesh();
                  sm->useSharedVertices = false;
                  sm->operationType = rop->operationType;
                  sm->setMaterialName(sec->getMaterialName());
                  // Copy vertex data; replicate buffers too
                  sm->vertexData = rop->vertexData->clone(true);
                  // Copy index data; replicate buffers too; delete the default, old one to avoid memory leaks
                  delete sm->indexData;
                  sm->indexData = rop->indexData->clone(true);
            }
        // update bounds
            m->_setBounds(mAABB);
            m->_setBoundingSphereRadius(mRadius);

            m->load();

            return m;


      }
      //-----------------------------------------------------------------------------
00711       void ManualObject::setUseIdentityProjection(bool useIdentityProjection)
      {
            // Set existing
            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  (*i)->setUseIdentityProjection(useIdentityProjection);
            }
            
            // Save setting for future sections
            mUseIdentityProjection = useIdentityProjection;
      }
      //-----------------------------------------------------------------------------
00723       void ManualObject::setUseIdentityView(bool useIdentityView)
      {
            // Set existing
            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  (*i)->setUseIdentityView(useIdentityView);
            }

            // Save setting for future sections
            mUseIdentityView = useIdentityView;
      }
    //-----------------------------------------------------------------------
00735       ManualObject::ManualObjectSection* ManualObject::getSection(unsigned int index) const
    {
        if (index >= mSectionList.size())
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
            "Index out of bounds.",
            "ManualObject::getSection");
        return mSectionList[index];
    }
    //-----------------------------------------------------------------------
00744       unsigned int ManualObject::getNumSections(void) const
    {
        return static_cast< unsigned int >( mSectionList.size() );
    }
      //-----------------------------------------------------------------------------
00749       const String& ManualObject::getMovableType(void) const
      {
            return ManualObjectFactory::FACTORY_TYPE_NAME;
      }
      //-----------------------------------------------------------------------------
00754       const AxisAlignedBox& ManualObject::getBoundingBox(void) const
      {
            return mAABB;
      }
      //-----------------------------------------------------------------------------
00759       Real ManualObject::getBoundingRadius(void) const
      {
            return mRadius;
      }
      //-----------------------------------------------------------------------------
00764       void ManualObject::_updateRenderQueue(RenderQueue* queue)
      {
            for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
            {
                  // Skip empty sections (only happens if non-empty first, then updated)
                  RenderOperation* rop = (*i)->getRenderOperation();
                  if (rop->vertexData->vertexCount == 0 ||
                        (rop->useIndexes && rop->indexData->indexCount == 0))
                        continue;

                  if (mRenderQueueIDSet)
                        queue->addRenderable(*i, mRenderQueueID);
                  else
                        queue->addRenderable(*i);
            }
      }
      //-----------------------------------------------------------------------------
00781       EdgeData* ManualObject::getEdgeList(void)
      {
            // Build on demand
            if (!mEdgeList && mAnyIndexed)
            {
                  EdgeListBuilder eb;
                  size_t vertexSet = 0;
                  bool anyBuilt = false;
                  for (SectionList::iterator i = mSectionList.begin(); i != mSectionList.end(); ++i)
                  {
                        RenderOperation* rop = (*i)->getRenderOperation();
                        // Only indexed triangle geometry supported for stencil shadows
                        if (rop->useIndexes && rop->indexData->indexCount != 0 && 
                              (rop->operationType == RenderOperation::OT_TRIANGLE_FAN ||
                               rop->operationType == RenderOperation::OT_TRIANGLE_LIST ||
                               rop->operationType == RenderOperation::OT_TRIANGLE_STRIP))
                        {
                              eb.addVertexData(rop->vertexData);
                              eb.addIndexData(rop->indexData, vertexSet++);
                              anyBuilt = true;
                        }
                  }

                  if (anyBuilt)
                        mEdgeList = eb.build();

            }
            return mEdgeList;
      }
      //---------------------------------------------------------------------
00811       bool ManualObject::hasEdgeList()
      {
            return getEdgeList() != 0;
      }
      //-----------------------------------------------------------------------------
      ShadowCaster::ShadowRenderableListIterator
00817       ManualObject::getShadowVolumeRenderableIterator(
            ShadowTechnique shadowTechnique, const Light* light,
            HardwareIndexBufferSharedPtr* indexBuffer,
            bool extrude, Real extrusionDistance, unsigned long flags)
      {
            assert(indexBuffer && "Only external index buffers are supported right now");
            assert((*indexBuffer)->getType() == HardwareIndexBuffer::IT_16BIT &&
                  "Only 16-bit indexes supported for now");

        EdgeData* edgeList = getEdgeList();
        if (!edgeList)
        {
            return ShadowRenderableListIterator(
                mShadowRenderables.begin(), mShadowRenderables.end());
        }

            // Calculate the object space light details
            Vector4 lightPos = light->getAs4DVector();
            Matrix4 world2Obj = mParentNode->_getFullTransform().inverseAffine();
            lightPos = world2Obj.transformAffine(lightPos);


            // Init shadow renderable list if required (only allow indexed)
            bool init = mShadowRenderables.empty() && mAnyIndexed;

            EdgeData::EdgeGroupList::iterator egi;
            ShadowRenderableList::iterator si, siend;
            ManualObjectSectionShadowRenderable* esr = 0;
            SectionList::iterator seci;
            if (init)
                  mShadowRenderables.resize(edgeList->edgeGroups.size());

            siend = mShadowRenderables.end();
            egi = edgeList->edgeGroups.begin();
            seci = mSectionList.begin();
            for (si = mShadowRenderables.begin(); si != siend; ++seci)
            {
            // Skip non-indexed geometry
            if (!(*seci)->getRenderOperation()->useIndexes)
            {
                continue;
            }

                  if (init)
                  {
                        // Create a new renderable, create a separate light cap if
                        // we're using a vertex program (either for this model, or
                        // for extruding the shadow volume) since otherwise we can
                        // get depth-fighting on the light cap
                        MaterialPtr mat = (*seci)->getMaterial();
                        mat->load();
                        bool vertexProgram = false;
                        Technique* t = mat->getBestTechnique();
                        for (int p = 0; p < t->getNumPasses(); ++p)
                        {
                              Pass* pass = t->getPass(p);
                              if (pass->hasVertexProgram())
                              {
                                    vertexProgram = true;
                                    break;
                              }
                        }
                        *si = new ManualObjectSectionShadowRenderable(this, indexBuffer,
                              egi->vertexData, vertexProgram || !extrude);
                  }
                  // Get shadow renderable
                  esr = static_cast<ManualObjectSectionShadowRenderable*>(*si);
                  HardwareVertexBufferSharedPtr esrPositionBuffer = esr->getPositionBuffer();
                  // Extrude vertices in software if required
                  if (extrude)
                  {
                        extrudeVertices(esrPositionBuffer,
                              egi->vertexData->vertexCount,
                              lightPos, extrusionDistance);

                  }

            ++si;
            ++egi;
            }
            // Calc triangle light facing
            updateEdgeListLightFacing(edgeList, lightPos);

            // Generate indexes and update renderables
            generateShadowVolume(edgeList, *indexBuffer, light,
                  mShadowRenderables, flags);


            return ShadowRenderableListIterator(
                  mShadowRenderables.begin(), mShadowRenderables.end());


      }
      //-----------------------------------------------------------------------------
      //-----------------------------------------------------------------------------
      //-----------------------------------------------------------------------------
      ManualObject::ManualObjectSection::ManualObjectSection(ManualObject* parent,
            const String& materialName,   RenderOperation::OperationType opType)
            : mParent(parent), mMaterialName(materialName)
      {
            mRenderOperation.operationType = opType;
            // default to no indexes unless we're told
            mRenderOperation.useIndexes = false;
            mRenderOperation.vertexData = new VertexData();
            mRenderOperation.vertexData->vertexCount = 0;

      }
      //-----------------------------------------------------------------------------
      ManualObject::ManualObjectSection::~ManualObjectSection()
      {
            delete mRenderOperation.vertexData;
            delete mRenderOperation.indexData; // ok to delete 0
      }
      //-----------------------------------------------------------------------------
00931       RenderOperation* ManualObject::ManualObjectSection::getRenderOperation(void)
      {
            return &mRenderOperation;
      }
      //-----------------------------------------------------------------------------
00936       const MaterialPtr& ManualObject::ManualObjectSection::getMaterial(void) const
      {
            if (mMaterial.isNull())
            {
                  // Load from default group. If user wants to use alternate groups,
                  // they can define it and preload
                  mMaterial = MaterialManager::getSingleton().load(mMaterialName,
                        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
            }
            return mMaterial;
      }
      //-----------------------------------------------------------------------------
00948       void ManualObject::ManualObjectSection::setMaterialName(const String& name)
      {
            if (mMaterialName != name)
            {
                  mMaterialName = name;
                  mMaterial.setNull();
            }
      }
      //-----------------------------------------------------------------------------
00957       void ManualObject::ManualObjectSection::getRenderOperation(RenderOperation& op)
      {
            // direct copy
            op = mRenderOperation;
      }
      //-----------------------------------------------------------------------------
00963       void ManualObject::ManualObjectSection::getWorldTransforms(Matrix4* xform) const
      {
            xform[0] = mParent->_getParentNodeFullTransform();
      }
      //-----------------------------------------------------------------------------
00968       const Quaternion& ManualObject::ManualObjectSection::getWorldOrientation(void) const
      {
            return mParent->getParentNode()->_getDerivedOrientation();
      }
      //-----------------------------------------------------------------------------
00973       const Vector3& ManualObject::ManualObjectSection::getWorldPosition(void) const
      {
            return mParent->getParentNode()->_getDerivedPosition();
      }
      //-----------------------------------------------------------------------------
00978       Real ManualObject::ManualObjectSection::getSquaredViewDepth(const Ogre::Camera *cam) const
      {
            Node* n = mParent->getParentNode();
            assert(n);
            return n->getSquaredViewDepth(cam);
      }
      //-----------------------------------------------------------------------------
00985       const LightList& ManualObject::ManualObjectSection::getLights(void) const
      {
            return mParent->queryLights();
      }
      //-----------------------------------------------------------------------------
      //--------------------------------------------------------------------------
      ManualObject::ManualObjectSectionShadowRenderable::ManualObjectSectionShadowRenderable(
            ManualObject* parent, HardwareIndexBufferSharedPtr* indexBuffer,
            const VertexData* vertexData, bool createSeparateLightCap,
            bool isLightCap)
            : mParent(parent)
      {
            // Initialise render op
            mRenderOp.indexData = new IndexData();
            mRenderOp.indexData->indexBuffer = *indexBuffer;
            mRenderOp.indexData->indexStart = 0;
            // index start and count are sorted out later

            // Create vertex data which just references position component (and 2 component)
            mRenderOp.vertexData = new VertexData();
            // Map in position data
            mRenderOp.vertexData->vertexDeclaration->addElement(0,0,VET_FLOAT3, VES_POSITION);
            ushort origPosBind =
                  vertexData->vertexDeclaration->findElementBySemantic(VES_POSITION)->getSource();
            mPositionBuffer = vertexData->vertexBufferBinding->getBuffer(origPosBind);
            mRenderOp.vertexData->vertexBufferBinding->setBinding(0, mPositionBuffer);
            // Map in w-coord buffer (if present)
            if(!vertexData->hardwareShadowVolWBuffer.isNull())
            {
                  mRenderOp.vertexData->vertexDeclaration->addElement(1,0,VET_FLOAT1, VES_TEXTURE_COORDINATES, 0);
                  mWBuffer = vertexData->hardwareShadowVolWBuffer;
                  mRenderOp.vertexData->vertexBufferBinding->setBinding(1, mWBuffer);
            }
            // Use same vertex start as input
            mRenderOp.vertexData->vertexStart = vertexData->vertexStart;

            if (isLightCap)
            {
                  // Use original vertex count, no extrusion
                  mRenderOp.vertexData->vertexCount = vertexData->vertexCount;
            }
            else
            {
                  // Vertex count must take into account the doubling of the buffer,
                  // because second half of the buffer is the extruded copy
                  mRenderOp.vertexData->vertexCount =
                        vertexData->vertexCount * 2;
                  if (createSeparateLightCap)
                  {
                        // Create child light cap
                        mLightCap = new ManualObjectSectionShadowRenderable(parent,
                              indexBuffer, vertexData, false, true);
                  }
            }
      }
      //--------------------------------------------------------------------------
      ManualObject::ManualObjectSectionShadowRenderable::~ManualObjectSectionShadowRenderable()
      {
            delete mRenderOp.indexData;
            delete mRenderOp.vertexData;
      }
      //--------------------------------------------------------------------------
01047       void ManualObject::ManualObjectSectionShadowRenderable::getWorldTransforms(
            Matrix4* xform) const
      {
            // pretransformed
            *xform = mParent->_getParentNodeFullTransform();
      }
      //--------------------------------------------------------------------------
      const Quaternion&
01055             ManualObject::ManualObjectSectionShadowRenderable::getWorldOrientation(void) const
      {
            return mParent->getParentNode()->_getDerivedOrientation();
      }
      //--------------------------------------------------------------------------
      const Vector3&
01061             ManualObject::ManualObjectSectionShadowRenderable::getWorldPosition(void) const
      {
            return mParent->getParentNode()->_getDerivedPosition();
      }
      //-----------------------------------------------------------------------------
      //-----------------------------------------------------------------------------
      String ManualObjectFactory::FACTORY_TYPE_NAME = "ManualObject";
      //-----------------------------------------------------------------------------
01069       const String& ManualObjectFactory::getType(void) const
      {
            return FACTORY_TYPE_NAME;
      }
      //-----------------------------------------------------------------------------
01074       MovableObject* ManualObjectFactory::createInstanceImpl(
            const String& name, const NameValuePairList* params)
      {
            return new ManualObject(name);
      }
      //-----------------------------------------------------------------------------
01080       void ManualObjectFactory::destroyInstance( MovableObject* obj)
      {
            delete obj;
      }



}

Generated by  Doxygen 1.6.0   Back to index