//
// CheetahBullet package.
//
// 20110512: first

var VERSION = "1.0b8";

var simFile_ext = "chdata";

var targetCount = 10;

var toRAD = Math.PI/180;
var toDEG = 180/Math.PI;

function buildUI(obj) {
    
    obj.setParameter('name','CheetahBullet Polygon Rep');
    
    obj.addParameterInt("frame", 0, 0, 1000000, true, true);
    obj.addParameterString("sim. file", "", true);
    obj.addParameterButton("set sim. file", "set", "setSimFile");
    obj.addParameterLink("sim. target", false);
    
    obj.addParameterSeparator("Smooth");
    obj.addParameterSelector("smooth",["normalFlat","normalPhong","normalContraint"],true,true);
    obj.addParameterFloat("smooth angle", 45.0, 5.0, 90.0, true, true);
    
    obj.addParameterSeparator("References");
    obj.addParameterBool("copy hard edge", 0, 0, 1, false, true);
    obj.addParameterSelector("copy polysel type", ["none", "each target self", "target number"], false, true);
    
    for (var i = 1;i <= targetCount;i++) {
        obj.addParameterLink("target "+i, false);
    }
    
    obj.setParameter("smooth",2);
}

function buildObject(obj) {
    
    //print('----');
    var frame = obj.getParameter("frame");
    var target = obj.getParameter("sim. target");
    var file = obj.getParameter("sim. file");
    
    if (!target) return;
    if (!file) return;
    
    var tmp = new File( file );
    tmp.open( READ_MODE, LITTLE_ENDIAN );
    if (! tmp.isOpen()) {
        print('sim. file does not exist');
        return;
    }
    
    // getting target
    var copyList = [];
    var copyIds = [];
    for (var i = 1;i <= targetCount;i++) {
        var copyTarget = obj.getParameter("target "+i);
        if (copyTarget) {
            copyList.push( copyTarget.getParameter("name") );
            copyIds.push( i );
        }
    }
    
    //print('--parsing sim. file');
    var i,j,k;
    var frame_total = tmp.readUInt();
    var info = [];
    
    //print( 'frame_total:'+frame_total );
    for (i = 0;i < frame_total;i++) {
        var f = tmp.readInt();
        var oc = tmp.readInt();
        var stride = tmp.readInt();
        
        if (frame != f) { // skip
            tmp.seek(stride, SEEK_CUR);
        } else {
            for (var j = 0;j < oc;j++) {
                var type = [];
                type[0] = tmp.readInt(); // index
                type[1] = tmp.readInt(); // rigid:0 or soft:1
                type[2] = tmp.readInt(); // vertexCount for soft
                type[3] = tmp.readInt(); // triangleCount for soft
                if (type[1] == 0) { // rigid
                    var mat = new Mat4D();
                    mat.m00 = tmp.readFloat(); mat.m10 = tmp.readFloat(); mat.m20 = tmp.readFloat(); mat.m30 = tmp.readFloat();
                    mat.m01 = tmp.readFloat(); mat.m11 = tmp.readFloat(); mat.m21 = tmp.readFloat(); mat.m31 = tmp.readFloat();
                    mat.m02 = tmp.readFloat(); mat.m12 = tmp.readFloat(); mat.m22 = tmp.readFloat(); mat.m32 = tmp.readFloat();
                    mat.m03 = tmp.readFloat(); mat.m13 = tmp.readFloat(); mat.m23 = tmp.readFloat(); mat.m33 = tmp.readFloat();
                    info.push( [ type, mat ] );
                } else if (type[1] == 1) { // soft
                    info.push( [ type, tmp.getpos() ] );
                    tmp.seek(type[2]*4*3, SEEK_CUR);
                } else if (type[1] == 2) { // particle
                    info.push( [ type, tmp.getpos() ] );
                    tmp.seek( 4*3 + 4*3, SEEK_CUR); // pos + rot
                } else if (type[1] == 3) { // spline
                    info.push( [ type, tmp.getpos() ] );
                    tmp.seek(type[2]*4*3, SEEK_CUR); // same as soft
                } else if (type[1] == 10) { // compound
                    var mat = new Mat4D();
                    mat.m00 = tmp.readFloat(); mat.m10 = tmp.readFloat(); mat.m20 = tmp.readFloat(); mat.m30 = tmp.readFloat();
                    mat.m01 = tmp.readFloat(); mat.m11 = tmp.readFloat(); mat.m21 = tmp.readFloat(); mat.m31 = tmp.readFloat();
                    mat.m02 = tmp.readFloat(); mat.m12 = tmp.readFloat(); mat.m22 = tmp.readFloat(); mat.m32 = tmp.readFloat();
                    mat.m03 = tmp.readFloat(); mat.m13 = tmp.readFloat(); mat.m23 = tmp.readFloat(); mat.m33 = tmp.readFloat();
                    info.push( [ type, mat ] );
                }
            }
            break;
        }
        if (tmp.getpos() >= tmp.size()) break;
    }
    
    /*
    print( 'info.length:'+info.length );
    for (i = 0;i < info.length;i++) {
        print(i+' ('+info[i]+')');
    }
     */
     
    var count = target.childCount();
    // target check and frame check
    if (target == undefined || info.length < 1) {
        return;
    }
    
    var core = obj.core();
    var copyPolySel = obj.getParameter("copy polysel type");
    
    // smooth
    obj.setParameter("normalType",obj.getParameter("smooth"),false);
    obj.setParameter("normalAngle",obj.getParameter("smooth angle"),false);
    
    var infoIndex = 0;
    var vertexOffset = 0;
    for (i = 0;i < count;i++) {
        var copy = target.childAtIndex(i);
        var copyName = copy.getParameter("name");
        // ignore other object
        if ( copy.family() != SPLINEFAMILY && copy.family() != PARTICLEFAMILY && copy.family() != NGONFAMILY && copy.type() != FOLDER) continue;
        if ( copy.getParameter("scriptName").indexOf("CheetahBullet Constraint.js") > -1 ) continue;
        //
        if (info.length <= infoIndex) {
            print(info.length+':'+infoIndex);
            print('wrong info [polygon]');
            return;
        }
        var targetId = 0;
        if ( copyList.indexOf( copyName ) == -1) {
            if (info[infoIndex][0][1] == 2) { // if particles
                infoIndex += info[infoIndex][0][3];
            } else {
                infoIndex++;
            }
            continue;
        } else {
            targetId = copyIds[ copyList.indexOf( copyName ) ];
        }
        if (copy.family() == NGONFAMILY) {
            if ((info[infoIndex][0][1] == 0 || info[infoIndex][0][1] == 1 || info[infoIndex][0][1] == 10)) { // rigid or soft or alter compound
                //print('--build [polygon]');
                var copyCore = copy.modCore();
                var pScale = copy.getParameter("scale");
                if (info[infoIndex][0][1] == 0 || info[infoIndex][0][1] == 10) { // rigid body or alter compound
                    var vertexCount = copyCore.vertexCount();
                    var cMat = info[infoIndex][1];
                    for (j = 0;j < vertexCount;j++) {
                        var vec = copyCore.vertex( j );
                        vec.x *= pScale.x; vec.y *= pScale.y; vec.z *= pScale.z;
                        core.addVertex(false, cMat.multiply( vec ) );
                    }
                } else if (info[infoIndex][0][1] == 1) { // softbody
                    tmp.setpos(info[infoIndex][1]);
                    var vertexCount = info[infoIndex][0][2];
                    if (vertexCount != copyCore.vertexCount()) continue;
                    
                    for (j = 0;j < vertexCount;j++) {
                        var vec = new Vec3D( tmp.readFloat(), tmp.readFloat(), tmp.readFloat() );
                        core.addVertex(false, vec );
                    }
                }
                var polygonCount = copyCore.polygonCount();
                var polygonSize = 0;
                var copyHardEdge = obj.getParameter("copy hard edge");
                for (j = 0;j < polygonCount;j++) {
                    polygonSize = copyCore.polygonSize( j );
                    var vertices = [];
                    var uvCoords = [];
                    for (k = 0;k < polygonSize;k++) {
                        vertices.push( vertexOffset + copyCore.vertexIndex(j, k) );
                        uvCoords.push( copyCore.uvCoord( j, k ) );
                    }
                    var pi = core.addIndexPolygon( vertices.length, vertices );
                    for (k = 0;k < polygonSize;k++) {
                        core.setUVCoord( pi, k, uvCoords[k] );
                    }
                    if (copyHardEdge) {
                        for (k = 0;k < polygonSize;k++) {
                            core.setEdgeSelection( pi, k, CREASE, copyCore.edgeSelection( j, k, CREASE ) );
                        }
                    }
                    if (copyPolySel == 1) {
                        // copy polygon selection
                        for (k = 0;k < 16;k++) {
                            core.setActivePolygonSelection( k );
                            copyCore.setActivePolygonSelection( k );
                            core.setPolygonSelection( pi, copyCore.polygonSelection( j ) );
                        }
                    } else if (copyPolySel == 2) {
                        core.setActivePolygonSelection( targetId );
                        core.setPolygonSelection( pi, true);
                    }
                }
                vertexOffset += vertexCount;
                core.setActivePolygonSelection(0);
                copyCore.setActivePolygonSelection(0);
            }
            infoIndex++;
        } else if (copy.type() == FOLDER) {
            if (info[infoIndex][0][1] == 10) {
                var cCount = copy.childCount();
                for (ci = 0;ci < cCount;ci++) {
                    var cCopy = copy.childAtIndex( ci );
                    if (cCopy.family() == NGONFAMILY) {
                        var copyCore = cCopy.modCore();
                        var pScale = cCopy.getParameter("scale");
                        var vertexCount = copyCore.vertexCount();
                        var cMat = info[infoIndex][1];
                        var ccMat = cCopy.objMatrix();
                        for (j = 0;j < vertexCount;j++) {
                            var vec = copyCore.vertex( j );
                            vec = ccMat.multiply( vec );
                            vec.x *= pScale.x; vec.y *= pScale.y; vec.z *= pScale.z;
                            core.addVertex(false, cMat.multiply( vec ) );
                        }
                        var polygonCount = copyCore.polygonCount();
                        var polygonSize = 0;
                        var copyHardEdge = obj.getParameter("copy hard edge");
                        for (j = 0;j < polygonCount;j++) {
                            polygonSize = copyCore.polygonSize( j );
                            var vertices = [];
                            var uvCoords = [];
                            for (k = 0;k < polygonSize;k++) {
                                vertices.push( vertexOffset + copyCore.vertexIndex( j, k ) );
                                uvCoords.push( copyCore.uvCoord( j, k ) );
                            }
                            var pi = core.addIndexPolygon( vertices.length, vertices );
                            for (k = 0;k < polygonSize;k++) {
                                core.setUVCoord( pi, k, uvCoords[k] );
                            }
                            if (copyHardEdge) {
                                for (k = 0;k < polygonSize;k++) {
                                    core.setEdgeSelection( pi, k, CREASE, copyCore.edgeSelection( j, k, CREASE ) );
                                }
                            }
                            if (copyPolySel == 1) {
                                // copy polygon selection
                                for (k = 0;k < 16;k++) {
                                    core.setActivePolygonSelection( k );
                                    copyCore.setActivePolygonSelection( k );
                                    core.setPolygonSelection( pi, copyCore.polygonSelection( j ) );
                                }
                            } else if (copyPolySel == 2) {
                                core.setActivePolygonSelection( targetId );
                                core.setPolygonSelection( pi, true);
                            }
                        }
                        vertexOffset += vertexCount;
                        core.setActivePolygonSelection(0);
                        copyCore.setActivePolygonSelection(0);
                    }
                }
            }
            infoIndex++;
        }
    }
    tmp.close();
}

function setSimFile( obj ) {
    var simFile = OS.runOpenPanel(simFile_ext);
    
    if (simFile != null) {
        obj.setParameter("sim. file", simFile);
    }
}

function tagForScriptName(obj, scriptName) {
	var tagCount = obj.tagCount();
	var resultTag = false;
	for (var i = 0;i < tagCount;i++) {
		var tag = obj.tagAtIndex(i);
        var sn = tag.getParameter("scriptName");
		if (sn.indexOf(scriptName) != -1 && tag.getParameter("tagOn")) {
			resultTag = tag;
		}
	}
	return resultTag;
}

function Vec3D_normalize( vec ) {
    if (vec.norm() == 0) return (new Vec3D());
    return vec.multiply( 1/vec.norm() );
}

function Vec3D_toString( vec ) {
	return vec.x.toFixed(3) + ', ' + vec.y.toFixed(3) + ', ' + vec.z.toFixed(3);
}

function Mat4D_toString( mat ) {
    var str = '(' + mat.m00.toFixed(3) + ', ' + mat.m01.toFixed(3) + ', ' + mat.m02.toFixed(3) + ', ' + mat.m03.toFixed(3) + "\n";
    str += ' ' + mat.m10.toFixed(3) + ', ' + mat.m11.toFixed(3) + ', ' + mat.m12.toFixed(3) + ', ' + mat.m13.toFixed(3) + "\n";
    str += ' ' + mat.m20.toFixed(3) + ', ' + mat.m21.toFixed(3) + ', ' + mat.m22.toFixed(3) + ', ' + mat.m23.toFixed(3) + "\n";
    str += ' ' + mat.m30.toFixed(3) + ', ' + mat.m31.toFixed(3) + ', ' + mat.m32.toFixed(3) + ', ' + mat.m33.toFixed(3) + ")\n";
    return str; 
}

function printElapsedTime(label, time) {
	if (time/1000 > 60) {
		print( label + ':' + (time/1000).toFixed(2) + 'sec(s) ( ' + Math.floor(time/1000/60) + '.' + Math.floor((time/1000)%60) + ' )');
	} else {
		print( label + ':' + (time/1000).toFixed(2) + 'sec(s)' );
	}
}
