Vector ClosestPointPoly ( Vector const & V, VertexList const & vertices )
{
	if(vertices.size() == 0) return V;

	if(vertices.size() == 1) return vertices[0];

	if(vertices.size() == 2) return ClosestPointSeg( V, Segment3d(vertices[0],vertices[1]) );

	// ----------

	Vector closest = ClosestPointTri( V, Triangle3d(vertices[0],vertices[1],vertices[2]) );

	int nTris = vertices.size() - 2;

	for(int i = 1; i < nTris; i++)
	{
		Triangle3d tri( vertices[0], vertices[i+1], vertices[i+2] );

		Vector temp = ClosestPointTri(V,tri);

		closest = selectCloser(V,closest,temp);
	}

	return closest;
}
void Cylinder::buildTopCap(VertexList& vertices, IndexList& indices)
{
	UINT baseIndex = (UINT)vertices.size();

	// Duplicate cap vertices because the texture coordinates and normals differ.
	float y = 0.5f*mHeight;

	// vertices of ring
	float dTheta = 2.0f*PI/mNumSlices;
	for(UINT i = 0; i <= mNumSlices; ++i)
	{
		float x = mTopRadius*cosf(i*dTheta);
		float z = mTopRadius*sinf(i*dTheta);

		// Map [-1,1]-->[0,1] for planar texture coordinates.
		float u = +0.5f*x/mTopRadius + 0.5f;
		float v = -0.5f*z/mTopRadius + 0.5f;

		vertices.push_back( Vertex(x, y, z, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, u, v) );
	}

	// cap center vertex
	vertices.push_back( Vertex(0.0f, y, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.5f, 0.5f) );

	// index of center vertex
	UINT centerIndex = (UINT)vertices.size()-1;

	for(UINT i = 0; i < mNumSlices; ++i)
	{
		indices.push_back(centerIndex);
		indices.push_back(baseIndex + i+1);
		indices.push_back(baseIndex + i);
	}
}
Example #3
0
void Mesh::construct()
{
	if (!m_material || !m_geometry) {
		return;
	}

	destruct();

	glGenVertexArrays(1, &m_vertexArray);
	glBindVertexArray(m_vertexArray);

	// Fill vertex position data
	glGenBuffers(1, &m_vertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);

	VertexList vertices = m_geometry->vertices();
	glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), vertices.data(), GL_STATIC_DRAW);

	glVertexAttribPointer((GLint)ShaderAttribute::VertexPosition, 3, GL_FLOAT, GL_FALSE, 0, bufferOffset(0));
	glEnableVertexAttribArray((GLint)ShaderAttribute::VertexPosition);

	// Fill UV vertex data
	if (m_geometry->uvCount()) {
		glGenBuffers(1, &m_textureCoordinatesBuffer);
		glBindBuffer(GL_ARRAY_BUFFER, m_textureCoordinatesBuffer);

		UVList uvs = m_geometry->uvs();
		glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), uvs.data(), GL_STATIC_DRAW);

		glVertexAttribPointer((GLint)ShaderAttribute::VertexTextureCoordinates, 2, GL_FLOAT, GL_FALSE, 0, bufferOffset(0));
		glEnableVertexAttribArray((GLint)ShaderAttribute::VertexTextureCoordinates);
	}

	// Fill vertex normal data
	if (m_geometry->normalCount()) {
		glGenBuffers(1, &m_vertexNormalsBuffer);
		glBindBuffer(GL_ARRAY_BUFFER, m_vertexNormalsBuffer);

		VertexList normals = m_geometry->normals();
		glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), normals.data(), GL_STATIC_DRAW);

		glVertexAttribPointer((GLint)ShaderAttribute::VertexNormals, 3, GL_FLOAT, GL_FALSE, 0, bufferOffset(0));
		glEnableVertexAttribArray((GLint)ShaderAttribute::VertexNormals);
	}

	// Fill index buffer
	glGenBuffers(1, &m_indexBuffer);
	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indexBuffer);

	IndexList indices = m_geometry->indices();
	glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32_t), indices.data(), GL_STATIC_DRAW);

	glBindVertexArray(0);

	m_dirty = false;
}
Example #4
0
NodePtr KDTree::makeTree(size_t depth, const size_t& cellSize, VertexLists& t,
        const Domain& domain){
    /*
     * Tuple contains x, y, z  Dimensions Vertex list
     *
    */
    const size_t k = depth % m_K;
    VertexList vertices = t.at(k);

    if(vertices.size() == 0){
        return nullptr;
    }
    if(vertices.size() <= cellSize){
        return NodePtr(new Node(vertices, domain));
    }

    size_t median = (int) (vertices.size()-1)/2;
    VertexPtr& posElement = vertices.at(median);

    //Split lists by median element
    std::vector< ListPair > pairs;
    for(size_t i=0; i<m_K; ++i){
        pairs.push_back(splitListBy(k, t.at(i), posElement));
    }

    VertexLists left;
    VertexLists right;
    for(ListPair pair: pairs){
        left.push_back(std::get<0>(pair));
        right.push_back(std::get<1>(pair));
    }

    Domain leftBounds = domain;
    Domain rightBounds = domain;
    leftBounds.updateMax((*posElement)[k], k);
    rightBounds.updateMin((*posElement)[k], k);

    NodePtr leftNode;
    NodePtr rightNode;
    if(depth < 2){
    thread lT([&] { leftNode = makeTree(depth+1, cellSize, left, leftBounds); });
    thread rT([&] { rightNode = makeTree(depth+1, cellSize, right, rightBounds); });
    lT.join();
    rT.join();
    }else{
        leftNode = makeTree(depth+1, cellSize, left, leftBounds);
        rightNode = makeTree(depth+1, cellSize, right, rightBounds);
    }
    return NodePtr(new Node(leftNode, rightNode, domain));
};
Example #5
0
Mesh::Mesh(VertexList const& vertices)
: m_id(afth::UUID::v4())
{
    size_t size = vertices.size() * 3;
    float* arr = new float[size];
    VertexList::const_iterator it = vertices.begin(), end = vertices.end();
    for (size_t i = 0; it != end; ++it, i += 3)
    {
        std::memcpy(arr + i, (*it).coordinates().arr().data(), 3 * sizeof(float));
    }

    //glGenVertexArrays(1, &m_vertexArray);
    //glGenBuffers(1, &m_vertexBuffer);

    //glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer);
    //glBufferData(GL_ARRAY_BUFFER, size * sizeof(float), arr, GL_STATIC_DRAW);

    //glBindVertexArray(m_vertexArray);

    //GLint positionIndex = glGetAttribLocation(glProgramUniform1, "position");
    //glEnableVertexAttribArray(0);
    //glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

    //glBindBuffer(GL_ARRAY_BUFFER, 0);
    //glBindVertexArray(0);

    delete [] arr;
}
Drawable RenderingEngine::CreateDrawable(const ParametricSurface& surface, int flags) const
{
    // Create the VBO for the vertices.
    VertexList vertices;
    surface.GenerateVertices(vertices, flags);
    GLuint vertexBuffer;
    glGenBuffers(1, &vertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
    glBufferData(GL_ARRAY_BUFFER,
                 vertices.size() * sizeof(vertices[0]),
                 &vertices[0],
                 GL_STATIC_DRAW);
    
    // Create a new VBO for the indices if needed.
    int indexCount = surface.GetTriangleIndexCount();
    GLuint indexBuffer;
    IndexList indices(indexCount);
    surface.GenerateTriangleIndices(indices);
    glGenBuffers(1, &indexBuffer);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                 indexCount * sizeof(GLushort),
                 &indices[0],
                 GL_STATIC_DRAW);
    
    // Fill in a descriptive struct and return it.
    Drawable drawable;
    drawable.IndexBuffer = indexBuffer;
    drawable.VertexBuffer = vertexBuffer;
    drawable.IndexCount = indexCount;
    drawable.Flags = flags;
    return drawable;
}
Example #7
0
	void VertexListToBufP(std::vector<float> &dst,const VertexList &list){
		dst.clear();
		dst.reserve(list.size()*3);
		for(VertexList::const_iterator i = list.begin();i!=list.end();i++){
			dst.push_back((*i).pos.x);
			dst.push_back((*i).pos.y);
			dst.push_back((*i).pos.z);
		}
	}
// copyVertexListToPointList a vector for Vec3 into a vector of Point's.
void copyVertexListToPointList(const VertexList& in,PointList& out)
{
    out.reserve(in.size());
    for(VertexList::const_iterator itr=in.begin();
        itr!=in.end();
        ++itr)
    {
        out.push_back(Point(0,*itr));
    }
}
    void StaticGeometryBuffer::_generateIndices()
    {
        _indexList.clear();

        VertexList  newVertList;
        //DebugText   debugText;

        for( uint i = 0; i < _vertexList.size(); ++i )
        {
            bool repeated = false;

            ///FLip uv's for openGL
            _vertexList[ i ].texCoord.y = 1 - _vertexList[ i ].texCoord.y;

            for( uint j = 0; j < newVertList.size(); ++j )
            {

                repeated = _isSameVertex( _vertexList[ i ], newVertList[ j ] );

                if( repeated )
                {
                    _indexList.push_back( j );
                    break;
                }
            }


            if( !repeated )
            {
                newVertList.push_back( _vertexList[ i ] );
                _indexList.push_back( newVertList.size() - 1 );
            }
        }

        _vertexList = newVertList;
    }
Example #10
0
//***************************************************************************************
// Name: BuildGeoSphere
// Desc: Function approximates a sphere by tesselating an icosahedron.
//***************************************************************************************
void BuildGeoSphere(UINT numSubdivisions, float radius, VertexList& vertices, IndexList& indices)
{
	// Put a cap on the number of subdivisions.
	numSubdivisions = Min(numSubdivisions, UINT(5));

	// Approximate a sphere by tesselating an icosahedron.

	const float X = 0.525731f; 
	const float Z = 0.850651f;

	D3DXVECTOR3 pos[12] = 
	{
		D3DXVECTOR3(-X, 0.0f, Z),  D3DXVECTOR3(X, 0.0f, Z),  
		D3DXVECTOR3(-X, 0.0f, -Z), D3DXVECTOR3(X, 0.0f, -Z),    
		D3DXVECTOR3(0.0f, Z, X),   D3DXVECTOR3(0.0f, Z, -X), 
		D3DXVECTOR3(0.0f, -Z, X),  D3DXVECTOR3(0.0f, -Z, -X),    
		D3DXVECTOR3(Z, X, 0.0f),   D3DXVECTOR3(-Z, X, 0.0f), 
		D3DXVECTOR3(Z, -X, 0.0f),  D3DXVECTOR3(-Z, -X, 0.0f)
	};

	DWORD k[60] = 
	{
		1,4,0,  4,9,0,  4,5,9,  8,5,4,  1,8,4,    
		1,10,8, 10,3,8, 8,3,5,  3,2,5,  3,7,2,    
		3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0, 
		10,1,6, 11,0,9, 2,11,9, 5,2,9,  11,2,7 
	};

	vertices.resize(12);
	indices.resize(60);

	for(int i = 0; i < 12; ++i)
		vertices[i] = pos[i];

	for(int i = 0; i < 60; ++i)
		indices[i] = k[i];

	for(UINT i = 0; i < numSubdivisions; ++i)
		Subdivide(vertices, indices);

	// Project vertices onto sphere and scale.
	for(size_t i = 0; i < vertices.size(); ++i)
	{
		D3DXVec3Normalize(&vertices[i], &vertices[i]);
		vertices[i] *= radius;
	}
}
Example #11
0
void ConvexPlanarPolygon::write(DataOutputStream* out) {
    // Write ConvexPlanarPolygon's identification.
    out->writeInt(IVECONVEXPLANARPOLYGON);
    // If the osg class is inherited by any other class we should also write this to file.
    //osg::Object*  obj = dynamic_cast<osg::Object*>(this);
    //if(obj){
    //    ((ive::Object*)(obj))->write(out);
    //}
    //else
    //    in_THROW_EXCEPTION("ConvexPlanarPolygon::write(): Could not cast this osg::ConvexPlanarPolygon to an osg::Object.");
    // Write ConvexPlanarPolygon's properties.

    // Write Vertex list
    VertexList vertexList = getVertexList();
    int size = vertexList.size();
    out->writeInt(size);
    for(int i=0; i<size; i++) {
        out->writeVec3(vertexList[i]);
    }

}
void GeometryExportFile::writeSprite( Object *o, ofstream &out )
{

   //  out << "OBJECT poly"<<endl;
    out << "  WORLD (" << endl;
    out << "  TEXTURES (" << endl;
    out << "    MAX_TEXTURES (10)" << endl;
    out << "    TEXTURE 'abstract_a032.gif' ()" << endl;
    out << "    TEXTURE 'andrew_wood.gif' ()" << endl;
    out << "    TEXTURE 'sydney.gif' ()" << endl;
    out << "    TEXTURE 'bla.png' ()" << endl;
    out << "    TEXTURE 'bla2.gif' ()" << endl;
    out << "  )" << endl;


   // Don't know how to get the name.
    out << "SPRITE 'sydney'(" << endl;


   // Add the texture.
   // We also need to add the texture to the top of the world file.
    TextureMaterial *tm = o->getTextureMaterial();

    if(tm != 0 && tm->texture != 0)
    {
      // Need to get the file name that the image will be in CS's VFS.
      //    out << "TEXNR('"<<tm->texture->getFilename()->ascii()\
      //      << "')" <<endl;
        out << "TEXNR('bla2.gif')" << endl;

    }

   // Write the frames.  err... "frame".  We done needs verts, and
   //  uv coordinates.

   // We are going to waste some vertices here.
   //
   // We are going to add an extra set of vertices
   //
   // for each face:
   //   add to the new vertex list, the vertices in the face.
   //   add to the new uv coords list, the uvs for the face.
   //
   // The triangle list will be made by consecutively using three vertices
   //  from the list of vertices.


    VertexList *vlist = o->getVerts();

    UVList *uvlist = o->getUVs();

    vector<Vector4> new_vert_list;

    vector<Vector4> new_uv_list;



    int num_verts = ( int ) vlist->size();

    int num_uvs = ( int ) uvlist->size();

   //DEBUG
   //  out << "num_verts is:" << num_verts << " num_uvs is:" << num_uvs <<endl;


    int num_faces = ( int ) o->numFaces();

    int tris = -1;


    for(int i = 0; i < num_faces; i++)
    {
        Face *face = o->getFace( i );
        vector<int> *face_vlist = face->getVerts();
        vector<int> *face_uvlist = face->getUVs();


        int v_size = ( int ) face_vlist->size();
        int uv_size = ( int ) face_uvlist->size();

        for(int ii = 0; ii < uv_size; ii++)
        {
            new_uv_list.push_back( face->getParentObject() ->getUVCoord(
                                                                       ( *face_uvlist ) [ ii ] ) ->getPosition() );
        }

        for(int ii = 0; ii < v_size; ii++)
        {
            new_vert_list.push_back( face->getParentObject() ->getVertex(
                                                                        ( *face_vlist ) [ ii ] ) ->getPosition() );
        }
    }


   // write out the frames... er just one frame for now.

   // DEBUG
   //  out << "new_vert_list size:" << new_vert_list.size() << endl;
   //  out << "new_uv_list size:" << new_uv_list.size() << endl;

   // Just place the name of the frame for now.
    out << "FRAME 'stand1' (";

    for(uint i = 0; i < new_vert_list.size(); i++)
    {
        out << "V(" << new_vert_list[ i ].x << "," << new_vert_list[ i ].y << ",";

      // The z axis are oposite for I3D and CS.
        out << new_vert_list[ i ].z * -1 << ":";
      // Have to convert systems, as cs uses x = 0, y = 0 at top left.
      //  Inovation 3d uses bottom left.
        out << new_uv_list[ i ].x << "," << ( 1.0 - new_uv_list[ i ].y ) << ")";
        out << endl;
    }

    out << ")" << endl;

   // write out the list of triangles.
    for(int i = 0; i < new_vert_list.size(); i += 3)
    {
        out << "TRIANGLE(" << i + 2 << "," << i + 1 << "," << i << ")" << endl;
    }


}
void GeometryExportFile::writeModel( Object *o, ofstream &out )
{

    out << 
    "{ 'MODL'\n"
    "   { 'SRC' \"Innovation 3D exported by WF geometry exporter V0.11\"" 
    "   }\n"
    "   { 'TRGT' \"World Foundy Game Engine (www.worldfoundry.org)\"\n" 
    "   }\n" << endl;

    out <<
    "   { 'NAME' \"" << o->getName() << "\"\n" 
    "   }\n";


    out.setf(std::ios::showpoint);

     //Vector4 pos;
    float texturex=0;
    float texturey=0;
    float color=0;
     //pos = o->getPosition();

    int oldWidth = out.width(8);
    char oldFill = out.fill('0');

    // kts i3d is a left handed coordinate system with positive y up, WF is left handed with positive z up
    // so I rotate -90 degrees around x putting y up (swap y&z, negate the new y)

    VertexList *vlist = o->getVerts();
    int size = (int)vlist->size();
    Vector4 vertpos;
    Vector4 uv;

    for(int i=0; i<size; i++)
    {
        vertpos = (*vlist)[i]->getPosition();
        VertexAndUV vuv;
        vuv.position = vertpos;

    }

    CreateVertUVList(o);
    WriteVertexList(out);

    out << "    { 'MATL' //flags: [FLAT_SHADED=0, GOURAUD_SHADED=1] [SOLID_COLOR=0, TEXTURE_MAPPED=2] [SINGLE_SIDED=0, TWO_SIDED=8]" << endl;

        //save materials here.

    ObjectDB *odb = I3D::getDB();

    TextureMaterial *m;
    for(int materialIndex=0; materialIndex<odb->numMaterials(); materialIndex++)
    {
        m = odb->getMaterial(materialIndex);

        _MaterialOnDisk mod;

        mod._materialFlags = 0;
        if(m->enable_texture)
            mod._materialFlags |= TEXTURE_MAPPED;

        for(int temp=0;temp<MATERIAL_NAME_LEN;temp++)
            mod.textureName[temp] = 0;

        if(m->texture)
            strncpy(mod.textureName, m->texture->getFilename()->ascii(), MATERIAL_NAME_LEN);
        mod.textureName[MATERIAL_NAME_LEN-1] = 0;    // make sure it is 0 terminated

        mod._color = ((((unsigned int)m->cDiffuse.r)<<16) |
                      (((unsigned int)m->cDiffuse.g)<<8) |
                      ((unsigned int)m->cDiffuse.b));

        out << "            //Material " << materialIndex << ": flags: " << mod._materialFlags << ", color: " << hex << mod._color << dec << ", texturename: \"" << mod.textureName << "\"" << endl;
        out << "        ";
                                                                  
        for(int index=0;index<sizeof(_MaterialOnDisk);index++)
        {
            out << (unsigned int)(((unsigned char*)&mod)[index]) << "y ";
        }
        out << " // #" << materialIndex << endl;

    }
    out << "    }" << endl;        

    // faces
    size = (int)o->numFaces();

    out << "    { 'FACE' // count = " << size << endl;

        
    for(int faceIndex=0; faceIndex<size; faceIndex++)
    {
        Face* face = o->getFace(faceIndex);
        vector<int> *vlist = face->getVerts();
        vector<int> *uvlist = face->getUVs();

        assert(vlist->size() >= 3);              // must be at least a triangle

        // output list of triangles for this face
        
        // make a fan of triangles, first vertex is the same for all polys
        int vert1 = LookupVertUVEntry(CreateVUV(*face,vlist, 0, o->getTextureMaterial()));
        // second point                                         
        int vert2 = LookupVertUVEntry(CreateVUV(*face,vlist, 1, o->getTextureMaterial()));
        
        for(int vertexIndex=2;vertexIndex<vlist->size();vertexIndex++)
        {
            VertexAndUV vuv3 = CreateVUV(*face,vlist, vertexIndex, o->getTextureMaterial());
            int vert3 = LookupVertUVEntry(vuv3);
            int materialIndex = -1;
    
            if(o->getTextureMaterial() != 0)
            {
                materialIndex = I3D::getDB()->getMaterialIndex(o->getTextureMaterial());
            }
            else
                cerr << "material not set!" << endl;
            
            out << "        " << vert1 << "w " << vert2 << "w " << vert3 << "w " << materialIndex << "w   // face #" << faceIndex << ", poly #" << vertexIndex << endl;    
            
            // vert2 on next fan is vert3 from this fan
            vert2 = vert3;
        }
    }

    out << "    }" << endl;


    out << "}" << endl;
}
void FastMassSpring::initEdgeGraph(
  FaceList& face_list,
  VertexList& vertex_list,
  AdjList& vertex_share_faces)
{
  this->P_Num = vertex_list.size() / 3;

  // building edge graph
  this->strech_edges.clear();
  {
    int ptid[3] = {0, 0, 0};
    for (decltype(face_list.size()) i = 0; i < face_list.size() / 3; ++i)
    {
      ptid[0] = face_list[3 * i + 0];
      ptid[1] = face_list[3 * i + 1];
      ptid[2] = face_list[3 * i + 2];
      // the order of start point and end point doesn't matter
      this->strech_edges.push_back(
        ptid[0] < ptid[1] ? Edge(ptid[0], ptid[1]) : Edge(ptid[1], ptid[0]));
      this->strech_edges.push_back(
        ptid[1] < ptid[2] ? Edge(ptid[1], ptid[2]) : Edge(ptid[2], ptid[1]));
      this->strech_edges.push_back(
        ptid[2] < ptid[0] ? Edge(ptid[2], ptid[0]) : Edge(ptid[0], ptid[2]));
    }
    std::sort(this->strech_edges.begin(), this->strech_edges.end());
    std::vector<Edge>::iterator iter = 
      std::unique(this->strech_edges.begin(), this->strech_edges.end());
    this->strech_edges.erase(iter, strech_edges.end());
    this->strech_edges.shrink_to_fit();

    // store rest length
    float cur_r = 0.0;
    this->strech_r_length.clear();
    for (auto& i : this->strech_edges)
    {
      cur_r = 0.0;
      for (int j = 0; j < 3; ++j)
      {
        cur_r += pow(vertex_list[3 * i.first + j] - vertex_list[ 3 * i.second + j], 2);
      }
      this->strech_r_length.push_back(sqrt(cur_r));
    }
  }

  this->bending_edges.clear();
  {
    for (auto& i : this->strech_edges)
    {
      int cross_pi = -1;
      int cross_pj = -1;
      if (findShareVertex(
        cross_pi, cross_pj, i.first, i.second, vertex_share_faces, face_list))
      {
        this->bending_edges.push_back(
          cross_pi < cross_pj ? 
            Edge(cross_pi, cross_pj) : Edge(cross_pj, cross_pi));
      }
    }

    // store rest length
    float cur_r = 0.0;
    this->bending_r_length.clear();
    for (auto& i : this->bending_edges)
    {
      cur_r = 0.0;
      for (int j = 0; j < 3; ++j)
      {
        cur_r += pow(vertex_list[3 * i.first + j] - vertex_list[ 3 * i.second + j], 2);
      }
      this->bending_r_length.push_back(sqrt(cur_r));
    }
  }

  // init d vector
  this->computedVector();
}
void Sphere::buildStacks(VertexList& vertices, IndexList& indices)
{
	float phiStep = PI/mNumStacks;

	// do not count the poles as rings
	UINT numRings = mNumStacks-1;

	// Compute vertices for each stack ring.
	for(UINT i = 1; i <= numRings; ++i)
	{
		float phi = i*phiStep;

		// vertices of ring
		float thetaStep = 2.0f*PI/mNumSlices;
		for(UINT j = 0; j <= mNumSlices; ++j)
		{
			float theta = j*thetaStep;

			Vertex v;

			// spherical to cartesian
			v.pos.x = mRadius*sinf(phi)*cosf(theta);
			v.pos.y = mRadius*cosf(phi);
			v.pos.z = mRadius*sinf(phi)*sinf(theta);

			// partial derivative of P with respect to theta
			v.tangent.x = -mRadius*sinf(phi)*sinf(theta);
			v.tangent.y = 0.0f;
			v.tangent.z = mRadius*sinf(phi)*cosf(theta);

			D3DXVec3Normalize(&v.normal, &v.pos);

			v.texC.x = theta / (2.0f*PI);
			v.texC.y = phi / PI;

			vertices.push_back( v );
		}
	}

	// poles: note that there will be texture coordinate distortion
	vertices.push_back( Vertex(0.0f, -mRadius, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, -1.0f, 0.0f, 0.0f, 1.0f) );
	vertices.push_back( Vertex(0.0f, mRadius, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f) );

	UINT northPoleIndex = (UINT)vertices.size()-1;
	UINT southPoleIndex = (UINT)vertices.size()-2;

	UINT numRingVertices = mNumSlices+1;

	// Compute indices for inner stacks (not connected to poles).
	for(UINT i = 0; i < mNumStacks-2; ++i)
	{
		for(UINT j = 0; j < mNumSlices; ++j)
		{
			indices.push_back(i*numRingVertices + j);
			indices.push_back(i*numRingVertices + j+1);
			indices.push_back((i+1)*numRingVertices + j);

			indices.push_back((i+1)*numRingVertices + j);
			indices.push_back(i*numRingVertices + j+1);
			indices.push_back((i+1)*numRingVertices + j+1);
		}
	}

	// Compute indices for top stack.  The top stack was written 
	// first to the vertex buffer.
	for(UINT i = 0; i < mNumSlices; ++i)
	{
		indices.push_back(northPoleIndex);
		indices.push_back(i+1);
		indices.push_back(i);
	}

	// Compute indices for bottom stack.  The bottom stack was written
	// last to the vertex buffer, so we need to offset to the index
	// of first vertex in the last ring.
	UINT baseIndex = (numRings-1)*numRingVertices;
	for(UINT i = 0; i < mNumSlices; ++i)
	{
		indices.push_back(southPoleIndex);
		indices.push_back(baseIndex+i);
		indices.push_back(baseIndex+i+1);
	}
}
void ProgressiveTriangleGeometry::FindEdgeToCollapse(VertexList& /*org_vertex_list*/,
	TriangleList& /*org_triangle_list*/, VertexList& vertex_list, TriangleList& triangle_list, Edge& edge) {
	if (triangle_list.empty())
		return;

	float current_error = 0.0f;
	float current_max_error = 0.0f;

	edge.v1_ = 0;
	edge.v2_ = 0;
	edge.triangle_list_.clear();

	// Calculate mean error.
	VertexList::iterator v_iter;
	for (v_iter = vertex_list.begin();
	     v_iter != vertex_list.end();
	     ++v_iter) {
		if (v_iter == vertex_list.begin()) {
			current_max_error = (*v_iter)->error_;
		} else if((*v_iter)->error_ > current_max_error) {
			current_max_error = (*v_iter)->error_;
		}

		current_error += (*v_iter)->error_;
	}

	current_error /= (float)vertex_list.size();

	float min_error = 0.0f;
	float min_error1 = 0.0f;	// Temporary error value storage for _edge->v1_.
	float min_error2 = 0.0f;	// Temporary error value storage for _edge->v2_.
	bool first = true;

	// Test vertex collaps on all triangles.
	TriangleList::iterator tri_iter;
	for (tri_iter = triangle_list.begin();
	     tri_iter != triangle_list.end();
	     ++tri_iter) {
		Triangle* triangle = *tri_iter;
		vec3 diff1;
		vec3 diff2;
		Vertex mid;

		// Test V1 and V2.
		mid.x() = (triangle->v1_->x() + triangle->v2_->x()) * 0.5f;
		mid.y() = (triangle->v1_->y() + triangle->v2_->y()) * 0.5f;
		mid.z() = (triangle->v1_->z() + triangle->v2_->z()) * 0.5f;

		// Calculate the distance between the new, merged position,
		// and the original vertex position.
		diff1.Set(mid.x() - triangle->v1_->twin_->x(),
		            mid.y() - triangle->v1_->twin_->y(),
		            mid.z() - triangle->v1_->twin_->z());
		diff2.Set(mid.x() - triangle->v2_->twin_->x(),
		            mid.y() - triangle->v2_->twin_->y(),
		            mid.z() - triangle->v2_->twin_->z());

		float error1 = diff1.GetLength() + triangle->v1_->error_;
		float error2 = diff2.GetLength() + triangle->v2_->error_;
		float error = (error1 + error2 + current_error) / 3.0f;

		if (first == true || error < min_error) {
			edge.v1_ = triangle->v1_;
			edge.v2_ = triangle->v2_;
			min_error1 = error1;
			min_error2 = error2;
			min_error = error;
			first = false;
		}

		// Test V2 and V3.
		mid.x() = (triangle->v2_->x() + triangle->v3_->x()) * 0.5f;
		mid.y() = (triangle->v2_->y() + triangle->v3_->y()) * 0.5f;
		mid.z() = (triangle->v2_->z() + triangle->v3_->z()) * 0.5f;

		// Calculate the distance between the new, merged position,
		// and the original vertex position.
		diff1.Set(mid.x() - triangle->v2_->twin_->x(),
		            mid.y() - triangle->v2_->twin_->y(),
		            mid.z() - triangle->v2_->twin_->z());
		diff2.Set(mid.x() - triangle->v3_->twin_->x(),
		            mid.y() - triangle->v3_->twin_->y(),
		            mid.z() - triangle->v3_->twin_->z());

		error1 = diff1.GetLength() + triangle->v1_->error_;
		error2 = diff2.GetLength() + triangle->v2_->error_;
		error = (error1 + error2 + current_error) / 3.0f;

		if (error < min_error) {
			edge.v1_ = triangle->v1_;
			edge.v2_ = triangle->v2_;
			min_error = error;
			min_error1 = error1;
			min_error2 = error2;
		}

		// Test V3 and V1.
		mid.x() = (triangle->v3_->x() + triangle->v1_->x()) * 0.5f;
		mid.y() = (triangle->v3_->y() + triangle->v1_->y()) * 0.5f;
		mid.z() = (triangle->v3_->z() + triangle->v1_->z()) * 0.5f;

		// Calculate the distance between the new, merged position,
		// and the original vertex position.
		diff1.Set(mid.x() - triangle->v3_->twin_->x(),
		            mid.y() - triangle->v3_->twin_->y(),
		            mid.z() - triangle->v3_->twin_->z());
		diff2.Set(mid.x() - triangle->v1_->twin_->x(),
		            mid.y() - triangle->v1_->twin_->y(),
		            mid.z() - triangle->v1_->twin_->z());

		error1 = diff1.GetLength() + triangle->v1_->error_;
		error2 = diff2.GetLength() + triangle->v2_->error_;
		error = (error1 + error2 + current_error) / 3.0f;

		if (error < min_error) {
			edge.v1_ = triangle->v1_;
			edge.v2_ = triangle->v2_;
			min_error = error;
			min_error1 = error1;
			min_error2 = error2;
		}

		if (min_error == 0.0f && edge.v1_ != 0 && edge.v2_ != 0)
			break;
	}

	edge.v1_->error_ = min_error1;
	edge.v2_->error_ = min_error2;

	// Now add all triangles to _edge that share the two vertices
	// _edge->v1_ and _edge->v2_.
	for (tri_iter = triangle_list.begin();
		tri_iter != triangle_list.end();
		++tri_iter) {
		Triangle* triangle = *tri_iter;
		if (triangle->HaveVertex(edge.v1_) &&
			triangle->HaveVertex(edge.v2_)) {
			edge.triangle_list_.push_back(triangle);
		}
	}
}
	//bool MeshXMLExporter::streamSubmesh(std::ostream &of, IGameNode *node, std::string &mtlName) {
	bool MeshXMLExporter::streamSubmesh(std::ostream &of, IGameObject *obj, std::string &mtlName) {
		
		//IGameObject* obj = node->GetIGameObject();
		if (obj->GetIGameType() != IGameMesh::IGAME_MESH)
			return false;

		// InitializeData() is important -- it performs all of the WSM/time eval for us; no face data without it
//		obj->InitializeData();
		IGameMesh* mesh = (IGameMesh*) obj;
		int vertCount = mesh->GetNumberOfVerts();
		int faceCount = mesh->GetNumberOfFaces();

		Tab<int> matIds = mesh->GetActiveMatIDs();
		Tab<DWORD> smGrpIds = mesh->GetActiveSmgrps();
		Tab<int> texMaps = mesh->GetActiveMapChannelNum();

		of << "\t\t<submesh ";
		
		if (mtlName.length() > 0)
			of << "material=\"" << mtlName << "\" ";

		of << "usesharedvertices=\"false\" use32bitindexes=\"";
		of << (vertCount > 65535);
		of << "\">" << std::endl;

		// *************** Export Face List ***************
		of << "\t\t\t<faces count=\"" << faceCount << "\">" << std::endl;

		//std::vector<UVVert

		// iterate the face list, putting vertices in the list for this submesh
		VertexList vertexList;

		for (int i=0; i<faceCount; i++) {

			of << "\t\t\t\t<face";
			FaceEx* face = mesh->GetFace(i);

			// do this for each vertex on the face
			for (int vi=0; vi<3; vi++) {
				Point3 p = mesh->GetVertex(face->vert[vi]);

				Vertex v(p.x, p.y, p.z);

				if (m_config.getExportVertexColours()) {
					Point3 c = mesh->GetColorVertex(face->vert[vi]);
					float a = mesh->GetAlphaVertex(face->vert[vi]);

					v.setColour(c.x, c.y, c.z, a);
				}

				Point3 n = mesh->GetNormal(face, vi);
				v.setNormal(n.x, n.y, n.z);

				// get each set of texcoords for this vertex
				for (int ch=0; ch < texMaps.Count(); ch++) {

					Point3 tv;
					DWORD indices[3];

					if (mesh->GetMapFaceIndex(texMaps[ch], i, indices))
						tv = mesh->GetMapVertex(texMaps[ch], indices[vi]);
					else
						tv = mesh->GetMapVertex(texMaps[ch], face->vert[vi]);

					v.addTexCoord(texMaps[ch], tv.x, tv.y, tv.z);
				}

				int actualVertexIndex = vertexList.add(v);

				of << " v" << vi + 1 << "=\"" << actualVertexIndex << "\"";
			}
 
			of << " />" << std::endl;
		}

		of << "\t\t\t</faces>" << std::endl;
		// *************** End Export Face List ***************


		// *************** Export Geometry ***************
		of << "\t\t\t<geometry vertexcount=\"" << vertexList.size() << "\">" << std::endl;

		// *************** Export Vertex Buffer ***************
		bool exportNormals = true;

		of << std::boolalpha;
		of << "\t\t\t\t<vertexbuffer positions=\"true\" normals=\"" << exportNormals << "\" colours_diffuse=\"" << m_config.getExportVertexColours() << "\" texture_coords=\"" << texMaps.Count() << "\"";
		
		for (int i=0; i<texMaps.Count(); i++)
			of << " texture_coords_dimensions_" << i << "=\"2\"";
		
		of << ">" << std::endl;

		int numVerts = vertexList.size();
		for (int i=0; i < numVerts; i++) 
		{
			const Vertex& v = vertexList.front();

			of << "\t\t\t\t\t<vertex>" << std::endl;
			of << std::showpoint;

			const Ogre::Vector3& p = v.getPosition();
			float x = p.x;
			float y = p.y;
			float z = p.z;

			of << "\t\t\t\t\t\t<position x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;

			if (m_config.getExportVertexColours()) 
			{

				float r = v.getColour().r;
				float g = v.getColour().g;
				float b = v.getColour().b;

				of << "\t\t\t\t\t\t<colour_diffuse value=\"\t" << r << "\t" << g << "\t" << b << "\" />" << std::endl;
			}

			if (exportNormals) {

				const Ogre::Vector3& n = v.getNormal();
				float x = n.x;
				float y = n.y;
				float z = n.z;

				of << "\t\t\t\t\t\t<normal x=\"" << x << "\" y=\"" << y << "\" z=\"" << z << "\" />" << std::endl;
			}

			// output the tex coords for each map used
			for (int ti=0; ti<texMaps.Count(); ti++) {
				int texMap = texMaps[ti];

				const Ogre::Vector3& uvw = v.getUVW(texMap); 

				switch (m_config.getTexCoord2D()) {
					case OgreMax::UV:
						of << "\t\t\t\t\t\t<texcoord u=\"" << uvw.x << "\" v=\"" << (1.0 - uvw.y) << "\" />" << std::endl; 
						break;
					case OgreMax::VW:
						of << "\t\t\t\t\t\t<texcoord v=\"" << uvw.y << "\" w=\"" << (1.0 - uvw.z) << "\" />" << std::endl; 
						break;
					case OgreMax::WU:
						of << "\t\t\t\t\t\t<texcoord w=\"" << uvw.z << "\" u=\"" << (1.0 - uvw.x) << "\" />" << std::endl; 
						break;
				}
			}
			
			of << std::noshowpoint;
			of << "\t\t\t\t\t</vertex>" << std::endl;
			vertexList.pop();
		}

		of << "\t\t\t\t</vertexbuffer>" << std::endl;
		// *************** End Export Vertex Buffer ***************

		of << "\t\t\t</geometry>" << std::endl;
		// *************** End Export Geometry ***********

		of << "\t\t</submesh>" << std::endl;

		// this skin extraction code based on an article found here:
		// http://www.cfxweb.net/modules.php?name=News&file=article&sid=1029
/*		Object *oRef = node->GetObjectRef();

		if (oRef->SuperClassID() == GEN_DERIVOB_CLASS_ID) {
			IDerivedObject *dObj = (IDerivedObject *)oRef;
			Modifier *oMod = dObj->GetModifier(0);

			if (oMod->ClassID() == SKIN_CLASSID) {

				// flag the export of a skeleton link element
				m_createSkeletonLink = true;

				// stream the boneassignments element
				streamBoneAssignments(of, oMod, node);
			}
		}

		of << "\t\t</submesh>" << std::endl;

		if (obj != tri)
			delete tri;
*/
//		node->ReleaseIGameObject();
		return true;
	}