xmlAssembly/BBoxesRep.cpp
 
 
 
xmlAssembly/BBoxesRep.cpp
//-
//**************************************************************************/
// Copyright 2012 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.
//**************************************************************************/
//+

#include <BBoxesRep.h>

#include "FnAssetInstance.h"
#include "FnAssetInstanceUtil.h"
#include "Representation.h"
#include "XMLStrings.h"

#include <maya/MPoint.h>
#include <maya/MTypes.h>
#include <maya/MStringArray.h>
#include <maya/MFnDagNode.h>
#include <maya/MPointArray.h>
#include <maya/MIntArray.h>
#include <maya/MFnMesh.h>
#include <maya/MFnTransform.h>
#include <maya/MGlobal.h>
#include <maya/MBoundingBox.h>
#include <maya/MDagPath.h>
#include <maya/MSelectionList.h>
#include <maya/MFnSet.h>

#include <string>
#include <map>
#include <vector>
using std::string;
using std::map;
using std::vector;

//==============================================================================
// CLASS BBoxesRep
//==============================================================================

//------------------------------------------------------------------------------
//
BBoxesRep::BBoxesRep(
    MObject assembly, const MString& guid
    )
    : BaseClass(assembly, guid)
{}

//------------------------------------------------------------------------------
//
BBoxesRep::~BBoxesRep()
{}

//------------------------------------------------------------------------------
//
bool BBoxesRep::activate()
{
    if( !isValidRepresentation())
    {
        //TODO::display errors
        return false;
    }
    if (BaseClass::activate())
    {
        return true;
    }
    
    MStringArray repInfo;
    FnAssetInstance::findRepInfo( fAssembly, fGuid, repInfo);
    if( repInfo.length() < 4)
    {
        //TODO::display errors
        return false;
    }

    //generate the name
    MFnDagNode assemblyNode( fAssembly);
    MString repNodeName = assemblyNode.name() + "_bboxes";
    MObject dynamicObj = createBBoxesShape( repNodeName, repInfo[ Representation::kRepData]);

        if (dynamicObj.isNull())
        {
                MGlobal::displayError("fail to create a BBoxes shape.");
                return false;
        }
        
        FnAssetInstanceUtil::addNodes( fAssembly, dynamicObj, true);
        registerRepNode( dynamicObj);

    return true;
}

//------------------------------------------------------------------------------
//
MString BBoxesRep::type()
{
    return XMLStrings::kwBBoxesType;
}

//------------------------------------------------------------------------------
//
MString BBoxesRep::getType() const
{
    return type();
}


void transformPoint(double *dst, double *src, double *m)
{
        dst[0] = src[0]*m[0]+src[1]*m[4]+src[2]*m[8]+m[12];
        dst[1] = src[0]*m[1]+src[1]*m[5]+src[2]*m[9]+m[13];
        dst[2] = src[0]*m[2]+src[1]*m[6]+src[2]*m[10]+m[14];
}

#include <math.h>

#define _pow10(x) pow(10.0,(x))
static double digtalTable[10] = {0.0,1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0};

const char* _sscanfnlf(int n, const char* string, double* ret )
{
        enum { NONE, POS_POWER, NEG_POWER, MAX } state;
        for(int j=0;j<n;++j)
        {
                double rtn = 0.0f;
                double negSign = 1.0f;
                double negPow = 1.0f;
                bool hasExp = false;

                state = NONE;
                while( true )
                {
                        switch( *string )
                        {
                        case '-':
                                negSign = -1.0f;
                                break;
                        case '0':
                        case '1':
                        case '2':
                        case '3':
                        case '4':
                        case '5':
                        case '6':
                        case '7':
                        case '8':
                        case '9':
                                if( state == NONE )
                                        state = POS_POWER;

                                if( state == POS_POWER )
                                {
                                        rtn *= 10.0f;
                                        rtn += digtalTable[*string-'0'];
                                }
                                else if( state == NEG_POWER )
                                {
                                        negPow *= 0.1f;
                                        rtn += digtalTable[*string-'0']*negPow;
                                }
                                break;

                        case '.':
                                state = NEG_POWER;
                                break;

                        case ',':
                        case ' ':
                        case '\0':
                        case 0x0d:
                        case 0x0a:
                        case '[':
                        case ']':
                        case '(':
                        case ')':
                                if( state != NONE )
                                        state = MAX;
                                break;
                        case 'e':
                        case 'E':
                                hasExp = true;
                                ret[j] = rtn*negSign;
                                negSign = 1.0f;
                                rtn = 0.0f;
                                state = NONE;
                                break;
                        }
                        string++;
                        if( state == MAX )
                                break;
                }

                if (hasExp)
                        ret[j] *= _pow10(rtn*negSign);
                else
                        ret[j] = rtn*negSign;
        }
        return string;
}

template <class MColor> struct less
{
        bool operator() (const MColor& c1, const MColor& c2) const
        {
                if (c1[0]<c2[0])
                        return true;
                else if (c1[0]>c2[0])
                        return false;
                else if (c1[1]<c2[1])
                        return true;
                else if (c1[1]>c2[1])
                        return false;
                else if (c1[2]<c2[2])
                        return true;
                else
                        return false;
        }
};

MObject BBoxesRep::createBBoxesShape(const MString& bboxName, const MString& data)
{
        MStatus status;
        
        MBoundingBox shapeBBox;

        double pointDataLocal[ 6];
        double pointDataInWorld[ 6];

        string bboxesData = data.asChar();

        static MFnTransform groupCreator;
        MObject groupObject = groupCreator.create();
        MFnTransform group(groupObject);
        static MFnMesh cubeCreator;

        static int polyConnectsData[] = {
                0, 1, 3, 2, 4, 6, 7, 5, 2, 3, 7, 6, 0, 2, 6, 4, 0, 4, 5, 1, 1, 5, 7, 3
        };
        double colorValues[3];
        double matrix[16];

        typedef map<MColor, int, less<MColor> > ColorMap;
        ColorMap colorMap;
        vector<MPointArray*> points;
        vector<MIntArray*> polyCounts;
        vector<MIntArray*> polyConnects;
        vector<unsigned int> pointIndex;

        size_t posCur = 0;
        size_t posNext = bboxesData.find("(",posCur+1);
        for(; posCur != string::npos ;posCur = posNext, posNext = bboxesData.find("(",posNext+1))
        {
                size_t pos1;
                for(size_t pos0 = posCur; pos0 != string::npos && (posNext == string::npos || pos0 < posNext); pos0 = pos1) {
                        const char* colorPos = _sscanfnlf(6, bboxesData.c_str()+pos0, pointDataLocal);

                        pos1 = bboxesData.find("(", pos0+1);

                        size_t pos3 = pos0;
                        pos3=bboxesData.find("[", pos3+1);
                        pos3=bboxesData.find("[", pos3+1);
                        pos3=bboxesData.find("[", pos3+1);
                        pos3=bboxesData.find("[", pos3+1);
                        pos3=bboxesData.find("[", pos3+1);
                        for(size_t pos2 = bboxesData.find("[", pos0);
                                pos2 < pos1 && pos2 != string::npos;
                                pos2 = pos3, pos3 = bboxesData.find("[", pos3+1)
                                , pos3 = bboxesData.find("[", pos3+1)
                                , pos3 = bboxesData.find("[", pos3+1)
                                , pos3 = bboxesData.find("[", pos3+1)) {
                                        if (pos3 != string::npos) {
                                                bboxesData[pos3-1]='\0';
                                        }

                                        _sscanfnlf(3, colorPos, colorValues);
                                        MColor color((float)colorValues[0],(float)colorValues[1],(float)colorValues[2]);

                                        colorPos = _sscanfnlf(16, bboxesData.c_str()+pos2, matrix);

                                        ColorMap::iterator result = colorMap.find(color);
                                        int colorIndex;
                                        if (result != colorMap.end()) {
                                                colorIndex = (*result).second;
                                        }
                                        else {
                                                colorIndex = (int)points.size();
                                                colorMap.insert(std::make_pair(color, colorIndex));
                                                points.push_back(new MPointArray);
                                                polyCounts.push_back(new MIntArray);
                                                polyConnects.push_back(new MIntArray);
                                                pointIndex.push_back(0U);
                                        }

                                        double tmpPoint[3];
                                        for( unsigned int y = 0; y < 2; ++y)
                                        {
                                                for( unsigned int z = 0; z < 2; ++z)
                                                {
                                                        for( unsigned int x = 0; x < 2; ++x, ++pointIndex[colorIndex])
                                                        {
                                                                tmpPoint[0] = pointDataLocal[ x * 3];
                                                                tmpPoint[1] = pointDataLocal[ y * 3 + 1];
                                                                tmpPoint[2] = pointDataLocal[ z * 3 + 2];

                                                                transformPoint(pointDataInWorld, tmpPoint, matrix);

                                                                shapeBBox.expand(MPoint(pointDataInWorld));

                                                                points[colorIndex]->append(pointDataInWorld[0], pointDataInWorld[1], pointDataInWorld[2]);
                                                        }
                                                }
                                        }

                                        for(unsigned int i = 0; i < 6; ++i) {
                                                polyCounts[colorIndex]->append(4);
                                        }
                                        for(unsigned int i = 0; i < 24; ++i) {
                                                polyConnects[colorIndex]->append(polyConnectsData[i] + pointIndex[colorIndex] - 8);
                                        }

                        }
                }
        }

        for(ColorMap::iterator i = colorMap.begin(); i != colorMap.end(); ++i) {
                MColor color = (*i).first;
                int index = (*i).second;
                int numOfBBox = pointIndex[index]/8;

                MObject bboxesNode = cubeCreator.create( numOfBBox*8, numOfBBox*6, *points[index], *polyCounts[index], *polyConnects[index]);

                delete points[index];
                delete polyCounts[index];
                delete polyConnects[index];

                group.addChild(bboxesNode);
                MFnMesh mesh(bboxesNode);

                MDagPath path(MDagPath::getAPathTo(bboxesNode));
                MString cmd = MString("polySoftEdge -a 0 -ch 0 ") + path.fullPathName();
                MGlobal::executeCommand(cmd);

                MDGModifier modifier;

                MString lambertName = MGlobal::executeCommandStringResult("shadingNode -asShader lambert");
                MSelectionList selection0;
                selection0.add(MString(lambertName));
                MObject shadingNodeObject;
                selection0.getDependNode(0, shadingNodeObject);

                MString shadingGroupName = MGlobal::executeCommandStringResult("sets -renderable 1 -noSurfaceShader 1 -empty");

                MSelectionList selection1;
                selection1.add(MString(shadingGroupName));
                MObject shadingGroupObject;
                selection1.getDependNode(0, shadingGroupObject);

                MFnDependencyNode shadingNode(shadingNodeObject);
                MPlug colorR = shadingNode.findPlug("colorR");
                colorR.setDouble(color[0]);
                MPlug colorG = shadingNode.findPlug("colorG");
                colorG.setDouble(color[1]);
                MPlug colorB = shadingNode.findPlug("colorB");
                colorB.setDouble(color[2]);
                MFnSet shadingGroupSet(shadingGroupObject);
                MStatus r = modifier.connect(shadingNode.findPlug("outColor"),shadingGroupSet.findPlug("surfaceShader"));
                shadingGroupSet.addMember(path);

                modifier.doIt();
        }
        
        MFnTransform assemblyTransform( fAssembly);

    //set scale pivot
    group.setScalePivot( shapeBBox.center(), MSpace::kObject, false);
    assemblyTransform.setScalePivot( shapeBBox.center(), MSpace::kObject, true);
    //set rotation pivot
    group.setRotatePivot( shapeBBox.center(), MSpace::kObject, false);
    assemblyTransform.setRotatePivot( shapeBBox.center(), MSpace::kObject, true);
    //rename the new created mesh
        group.setName( bboxName);

        return groupObject;
}