MeshBuilder/MeshBuilder.cpp

//**************************************************************************/
// Copyright (c) 2011 Autodesk, Inc.
// All rights reserved.
//
// Use of this software is subject to the terms of the Autodesk license
// agreement provided at the time of installation or download, or which
// otherwise accompanies this software in either electronic or hard copy form.
//
//**************************************************************************/
// DESCRIPTION: Mesh Builder
// CREATED: May 2011
//**************************************************************************/
                            
#include <QtCore/QObject>
#include "MeshBuilder.h"  

using namespace mudbox;

// Register this plugin. The "Initializer" method will be called when the plugin is loaded.
MB_PLUGIN( "MeshBuilder", "Build Simple Meshes", "Autodesk", "http://www.mudbox3d.com", Initializer );

// This function will be called then the plugin is loaded.
void Initializer(void)
{
    // Add a menu entry for this operation.
    Kernel()->Interface()->AddCallbackMenuItem( mudbox::Interface::menuMesh, QString::null, QObject::tr("Build Simple Meshes"), Execute);
}

void Execute(void)
{
    // Build the triangle plane mesh object, and name it.
    Mesh *pTriPlane = BuildTrianglePlane();
    pTriPlane->SetName("TriPlane"); 

    // Create a geometry object, which will be used as a container class for the mesh.
    // The geometry class can hold multiple levels of mesh.
    Geometry *pGeoPlane = CreateInstance<Geometry>();
    pGeoPlane->SetName("TriPlane Geometry");

    // Add the mesh that you created to the geometry object.  This mesh
    // is now the "level 0" mesh of the geometry.
    if (SubdivisionLevel *pTriPlaneSL = dynamic_cast<SubdivisionLevel *>(pTriPlane))
    {   
        // This mesh can be subdivided to add additional levels; 
        // use the "Mesh"->"Add New Subdivision Level" menu item.
        pGeoPlane->AddLevel(pTriPlaneSL); 
        pGeoPlane->SetActiveLevel(pTriPlaneSL);  
    }
    // Add the newly-created triangle plane to the scene.
    Kernel()->Scene()->AddGeometry(pGeoPlane);

    // Next, we build the quad cube mesh, and create a new geometry object
    // to hold it.  This is the same as above.
    Mesh *pQuadCube = BuildQuadCube();
    pQuadCube->SetName("QuadCube"); 
    Geometry *pGeoCube = dynamic_cast<Geometry *>(Geometry::CreateInstances());
    pGeoCube->SetName("QuadCube Geometry");
    SubdivisionLevel *pQuadCubeSL0 = dynamic_cast<SubdivisionLevel *>(pQuadCube);
    MB_ASSERT(pQuadCubeSL0);
    pGeoCube->AddLevel(pQuadCubeSL0); // to be level 0

    // Now we are going to create some additional subdivision levels for this cube
    // manually, to demonstrate how this can be done.
    SubdivisionLevel *pQuadCubeSL1 = pQuadCubeSL0->Subdivide(false, false, false); // Linear subdivision. 
    pGeoCube->AddLevel(pQuadCubeSL1); // to be level 1
    SubdivisionLevel *pQuadCubeSL2 = pQuadCubeSL1->Subdivide(false, true, false); // Catmull-Clark subdivision. 
    pGeoCube->AddLevel(pQuadCubeSL2); // to be level 2
    pGeoCube->SetActiveLevel(pQuadCubeSL2);
    Kernel()->Scene()->AddGeometry(pGeoCube);

    Kernel()->Scene()->SetActiveGeometry(pGeoCube);

    Kernel()->ViewPort()->Redraw(); // redraw the 3d view to display the new objects
    Kernel()->Interface()->RefreshUI();        // ensure that the new geometries will appear in the Object List.
}


Mesh *BuildTrianglePlane()
// This method creates a mesh object comprising a triangle plane.
{
    // Create an empty mesh object.
    Mesh *pMesh = Kernel()->Scene()->CreateMesh(Topology::typeTriangular);  
    
    MB_ASSERT(pMesh->VertexCount()       == 0);  // demonstrating that there are no vertices (yet)
    MB_ASSERT(pMesh->VertexNormalCount() == 0);  // and no normals
    MB_ASSERT(pMesh->TCCount()           == 0);  // and no texture coordinates (UVs)
    MB_ASSERT(pMesh->FaceCount()         == 0);  // and no faces

    // Create a list of vertices for the mesh (required). Each face has
    // a 3d coordinate.
    //v3______ v2
    //  |    /|
    //  |  /  |
    //v0|/____|v1
    pMesh->SetVertexCount(4);
    pMesh->SetVertexPosition(0, Vector(-400, 0, 0));   
    pMesh->SetVertexPosition(1, Vector(-200, 0, 0));
    pMesh->SetVertexPosition(2, Vector(-200, 200, 0));
    pMesh->SetVertexPosition(3, Vector(-400, 200, 0));
    MB_ASSERT(pMesh->VertexCount() == 4);

    // Create a list of faces (required).  Each face is a list of indices
    // into the vertex list, defining the corners of the face, counter-clockwise.
    pMesh->SetFaceCount(2);            // create 2 faces

    // The arguments to this next method are:
    //     The index of the face;
    //     Which corner of the face (a number from 0 to 2)
    //     The index of the vertex in the vertex list
    pMesh->SetTriangleIndex(0, 0, 0);  // triangle one.
    pMesh->SetTriangleIndex(0, 1, 1);
    pMesh->SetTriangleIndex(0, 2, 2);
    pMesh->SetTriangleIndex(1, 0, 0);  // triangle two.
    pMesh->SetTriangleIndex(1, 1, 2);
    pMesh->SetTriangleIndex(1, 2, 3);
    MB_ASSERT(pMesh->FaceCount() == 2);
    
    // Optionally, you can add texture coordinates (UVs) to your
    // mesh programmatically.  (If you don't, you can always add them
    // later using the menu command "Mesh" > "Create UVs".
    //
    //   t3______ t4        t5
    //  |    /       /|
    //  |  /       /  |
    //   t0|/     t1/____| t2
    //
    // A texture coordinate is set for each corner of each face in the
    // mesh.  Note that the same texture coordinate can be shared by
    // all the faces sharing a vertex.
    //
    // First, make your list of texture coordinates.
    pMesh->SetTCCount(6);
    pMesh->SetVertexTC(0, TC(0.1f, 0.1f)); // TC not allow to cross 1,2,3,...
    pMesh->SetVertexTC(1, TC(1.1f, 0.1f));
    pMesh->SetVertexTC(2, TC(1.9f, 0.1f));
    pMesh->SetVertexTC(3, TC(0.1f, 0.9f));
    pMesh->SetVertexTC(4, TC(0.9f, 0.9f));
    pMesh->SetVertexTC(5, TC(1.9f, 0.9f));
    MB_ASSERT(pMesh->TCCount() == 6); 

    // Now, point the corners of each triangular face into the texture
    // coordinate list.  The arguments to this method are:
    //     - the index of the face
    //     - the number of the face corner (from 0 to 2)
    //     - the index into the list of texture coordinates
    pMesh->SetTriangleTCI(0, 0, 0);
    pMesh->SetTriangleTCI(0, 1, 4);
    pMesh->SetTriangleTCI(0, 2, 3);
    pMesh->SetTriangleTCI(1, 0, 1);
    pMesh->SetTriangleTCI(1, 1, 2);
    pMesh->SetTriangleTCI(1, 2, 5);

    MB_ASSERT(pMesh->HasTC() == true);
        
    // Build the internal tables that tell us which faces are beside which others.
    // (This is required)
    pMesh->RecalculateAdjacency(); 
    
    // Calculate the normals (you don't need to set them manually, although that is also an option.)
    pMesh->RecalculateNormals();

    return pMesh;
}

Mesh *BuildQuadCube()
{
    // Create an empty mesh object
    Mesh *pMesh = Kernel()->Scene()->CreateMesh(Topology::typeQuadric);
    
    // Add a list of 8 vertices to it
    pMesh->SetVertexCount(8); 
    pMesh->SetVertexPosition(0, Vector(100, 0, 300));
    pMesh->SetVertexPosition(1, Vector(300, 0, 300));
    pMesh->SetVertexPosition(2, Vector(300, 0, 100));
    pMesh->SetVertexPosition(3, Vector(100, 0, 100));
    pMesh->SetVertexPosition(4, Vector(100, 200, 300));
    pMesh->SetVertexPosition(5, Vector(300, 200, 300));
    pMesh->SetVertexPosition(6, Vector(300, 200, 100));
    pMesh->SetVertexPosition(7, Vector(100, 200, 100));

    // Create the 6 faces of the cube.
    // Each face is a list of indices into the vertex list, defining
    // the corners of the face, counter-clockwise.
    //
    pMesh->SetFaceCount(6);
    unsigned int aFaceIndices[] = {
        0, 1, 5, 4, 2, 3, 7, 6, 1, 2, 6, 5, 3, 0, 4, 7, 4, 5, 6, 7, 1, 0, 3, 2
    };
    unsigned int iFIdx = 0;
    for (unsigned int iF = 0; iF < 6; ++iF)
    {
        pMesh->SetQuadIndex(iF, 0, aFaceIndices[iFIdx++]);
        pMesh->SetQuadIndex(iF, 1, aFaceIndices[iFIdx++]);
        pMesh->SetQuadIndex(iF, 2, aFaceIndices[iFIdx++]);
        pMesh->SetQuadIndex(iF, 3, aFaceIndices[iFIdx++]);
    }    

    // Build the internal tables that tell us which faces are beside which others.
    // (This is required)
    pMesh->RecalculateAdjacency();

    // Calculate the normals 
    pMesh->RecalculateNormals(); 

    MB_ASSERT(pMesh->HasTC() == false); // we don't set the tc values of this mesh manually.
    
    return pMesh; 
}