Exemple #1
0
int EditPatchMod::DoAttach(INode *node, PatchMesh *attPatch, RPatchMesh *rattPatch, bool & canUndo)
{
    ModContextList mcList;
    INodeTab nodes;

    if (!ip)
        return 0;

    ip->GetModContexts(mcList, nodes);

    if (mcList.Count() != 1)
    {
        nodes.DisposeTemporary();
        return 0;
    }

    EditPatchData *patchData =(EditPatchData*)mcList[0]->localData;
    if (!patchData)
    {
        nodes.DisposeTemporary();
        return 0;
    }
    patchData->BeginEdit(ip->GetTime());

    // If the mesh isn't yet cached, this will cause it to get cached.
    RPatchMesh *rpatch;
    PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
    if (!patch)
    {
        nodes.DisposeTemporary();
        return 0;
    }
    patchData->RecordTopologyTags(patch);
    RecordTopologyTags();

    // Transform the shape for attachment:
    // If reorienting, just translate to align pivots
    // Otherwise, transform to match our transform
    Matrix3 attMat(1);
    if (attachReorient)
    {
        Matrix3 thisTM = nodes[0]->GetNodeTM(ip->GetTime());
        Matrix3 thisOTMBWSM = nodes[0]->GetObjTMBeforeWSM(ip->GetTime());
        Matrix3 thisPivTM = thisTM * Inverse(thisOTMBWSM);
        Matrix3 otherTM = node->GetNodeTM(ip->GetTime());
        Matrix3 otherOTMBWSM = node->GetObjTMBeforeWSM(ip->GetTime());
        Matrix3 otherPivTM = otherTM * Inverse(otherOTMBWSM);
        Point3 otherObjOffset = node->GetObjOffsetPos();
        attMat = Inverse(otherPivTM) * thisPivTM;
    }
    else
    {
        attMat = node->GetObjectTM(ip->GetTime()) *
                 Inverse(nodes[0]->GetObjectTM(ip->GetTime()));
    }

    // RB 3-17-96 : Check for mirroring
    AffineParts parts;
    decomp_affine(attMat, &parts);
    if (parts.f < 0.0f)
    {
        int v[8], ct, ct2, j;
        Point3 p[9];

        for (int i = 0; i < attPatch->numPatches; i++)
        {

            // Re-order rpatch
            if (attPatch->patches[i].type == PATCH_QUAD)
            {
                UI_PATCH rpatch=rattPatch->getUIPatch (i);
                int ctU=rpatch.NbTilesU<<1;
                int ctV=rpatch.NbTilesV<<1;
                int nU;
                for (nU=0; nU<ctU; nU++)
                {
                    for (int nV=0; nV<ctV; nV++)
                    {
                        rattPatch->getUIPatch (i).getTileDesc (nU+nV*ctU)=rpatch.getTileDesc (ctU-1-nU+(ctV-1-nV)*ctU);
                    }
                }
                for (nU=0; nU<ctU+1; nU++)
                {
                    for (int nV=0; nV<ctV+1; nV++)
                    {
                        rattPatch->getUIPatch (i).setColor (nU+nV*(ctU+1), rpatch.getColor (ctU-nU+(ctV-nV)*ctU));
                    }
                }
            }

            // Re-order vertices
            ct = attPatch->patches[i].type == PATCH_QUAD ? 4 : 3;
            for (j = 0; j < ct; j++)
            {
                v[j] = attPatch->patches[i].v[j];
            }
            for (j = 0; j < ct; j++)
            {
                attPatch->patches[i].v[j] = v[ct - j - 1];
            }

            // Re-order vecs
            ct  = attPatch->patches[i].type == PATCH_QUAD ? 8 : 6;
            ct2 = attPatch->patches[i].type == PATCH_QUAD ? 5 : 3;
            for (j = 0; j < ct; j++)
            {
                v[j] = attPatch->patches[i].vec[j];
            }
            for (j = 0; j < ct; j++, ct2--)
            {
                if (ct2 < 0)
                    ct2 = ct - 1;
                attPatch->patches[i].vec[j] = v[ct2];
            }

            // Re-order enteriors
            if (attPatch->patches[i].type == PATCH_QUAD)
            {
                ct = 4;
                for (j = 0; j < ct; j++)
                {
                    v[j] = attPatch->patches[i].interior[j];
                }
                for (j = 0; j < ct; j++)
                {
                    attPatch->patches[i].interior[j] = v[ct - j - 1];
                }
            }

            // Re-order aux
            if (attPatch->patches[i].type == PATCH_TRI)
            {
                ct = 9;
                for (j = 0; j < ct; j++)
                {
                    p[j] = attPatch->patches[i].aux[j];
                }
                for (j = 0; j < ct; j++)
                {
                    attPatch->patches[i].aux[j] = p[ct - j - 1];
                }
            }

            // Re-order TV faces if present
            for (int chan = 0; chan < patch->getNumMaps(); ++chan)
            {
                if (attPatch->tvPatches[chan])
                {
                    ct = 4;
                    for (j = 0; j < ct; j++)
                    {
                        v[j] = attPatch->tvPatches[chan][i].tv[j];
                    }
                    for (j = 0; j < ct; j++)
                    {
                        attPatch->tvPatches[chan][i].tv[j] = v[ct - j - 1];
                    }
                }
            }
        }
    }

    int i;
    for (i = 0; i < attPatch->numVerts; ++i)
        attPatch->verts[i].p = attPatch->verts[i].p * attMat;
    for (i = 0; i < attPatch->numVecs; ++i)
        attPatch->vecs[i].p = attPatch->vecs[i].p * attMat;
    attPatch->computeInteriors();

    theHold.Begin();

    // Combine the materials of the two nodes.
    int mat2Offset = 0;
    Mtl *m1 = nodes[0]->GetMtl();
    Mtl *m2 = node->GetMtl();
    bool condenseMe = FALSE;
    if (m1 && m2 &&(m1 != m2))
    {
        if (attachMat == ATTACHMAT_IDTOMAT)
        {
            int ct = 1;
            if (m1->IsMultiMtl())
                ct = m1->NumSubMtls();
            for (int i = 0; i < patch->numPatches; ++i)
            {
                int mtid = patch->getPatchMtlIndex(i);
                if (mtid >= ct)
                    patch->setPatchMtlIndex(i, mtid % ct);
            }
            FitPatchIDsToMaterial(*attPatch, m2);
            if (condenseMat)
                condenseMe = TRUE;
        }
        // the theHold calls here were a vain attempt to make this all undoable.
        // This should be revisited in the future so we don't have to use the SYSSET_CLEAR_UNDO.
        theHold.Suspend();
        if (attachMat == ATTACHMAT_MATTOID)
        {
            m1 = FitMaterialToPatchIDs(*patch, m1);
            m2 = FitMaterialToPatchIDs(*attPatch, m2);
        }

        Mtl *multi = CombineMaterials(m1, m2, mat2Offset);
        if (attachMat == ATTACHMAT_NEITHER)
            mat2Offset = 0;
        theHold.Resume();
        // We can't be in face subobject mode, else we screw up the materials:
        DWORD oldSL = patch->selLevel;
        DWORD roldSL = patch->selLevel;
        patch->selLevel = PATCH_OBJECT;
        rpatch->SetSelLevel (EP_OBJECT);
        nodes[0]->SetMtl(multi);
        patch->selLevel = oldSL;
        rpatch->SetSelLevel (roldSL);
        m1 = multi;
        canUndo = FALSE;	// Absolutely cannot undo material combinations.
    }
    if (!m1 && m2)
    {
        // We can't be in face subobject mode, else we screw up the materials:
        DWORD oldSL = patch->selLevel;
        DWORD roldSL = rpatch->GetSelLevel();
        patch->selLevel = PATCH_OBJECT;
        rpatch->SetSelLevel (EP_OBJECT);
        nodes[0]->SetMtl(m2);
        patch->selLevel = oldSL;
        rpatch->SetSelLevel (roldSL);
        m1 = m2;
    }

    // Start a restore object...
    if (theHold.Holding())
        theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoAttach"));

    // Do the attach
    patch->Attach(attPatch, mat2Offset);
    rpatch->Attach(rattPatch, *patch);
    patchData->UpdateChanges(patch, rpatch);
    patchData->TempData(this)->Invalidate(PART_TOPO | PART_GEOM);

    // Get rid of the original node
    ip->DeleteNode(node);

    ResolveTopoChanges();
    theHold.Accept(GetString(IDS_TH_ATTACH));

    if (m1 && condenseMe)
    {
        // Following clears undo stack.
        patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
        m1 = CondenseMatAssignments(*patch, m1);
    }

    nodes.DisposeTemporary();
    ClearPatchDataFlag(mcList, EPD_BEENDONE);
    NotifyDependents(FOREVER, PART_TOPO | PART_GEOM, REFMSG_CHANGE);
    ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
    return 1;
}
Exemple #2
0
void ExtrudeMod::BuildPatchFromShape(TimeValue t,ModContext &mc, ObjectState * os, PatchMesh &pmesh) {
	ShapeObject *shape = (ShapeObject *)os->obj;

	float amount;
	int levels,capStart,capEnd,capType;

	pblock->GetValue(PB_AMOUNT,t,amount,FOREVER);
	pblock->GetValue(PB_SEGS,t,levels,FOREVER);
	if (levels<1) levels = 1;
	pblock->GetValue(PB_CAPSTART,t,capStart,FOREVER);
	pblock->GetValue(PB_CAPEND,t,capEnd,FOREVER);
	pblock->GetValue(PB_CAPTYPE,t,capType,FOREVER);

	BOOL texturing;
	pblock->GetValue(PB_MAPPING, TimeValue(0), texturing, FOREVER);
	BOOL genMatIDs;
	pblock->GetValue(PB_GEN_MATIDS, TimeValue(0), genMatIDs, FOREVER);
	BOOL useShapeIDs;
	pblock->GetValue(PB_USE_SHAPEIDS, TimeValue(0), useShapeIDs, FOREVER);
	BOOL smooth;
	pblock->GetValue(PB_SMOOTH, TimeValue(0), smooth, FOREVER);

	LimitValue(amount, -1000000.0f, 1000000.0f);

	// Get the basic dimension stuff
	float zSize = (float)fabs(amount);
	float baseZ = 0.0f;
	if(amount < 0.0f)
		baseZ = amount;

	// If the shape can convert itself to a BezierShape, have it do so!
	BezierShape bShape;
	if(shape->CanMakeBezier())
		shape->MakeBezier(t, bShape);
	else {
		PolyShape pShape;
		shape->MakePolyShape(t, pShape);
		bShape = pShape;	// UGH -- Convert it from a PolyShape -- not good!
		}
	
//DebugPrint(_T("Extrude organizing shape\n"));
	ShapeHierarchy hier;
	bShape.OrganizeCurves(t, &hier);
	// Need to flip the reversed polys...
	bShape.Reverse(hier.reverse);
	// ...and tell the hierarchy they're no longer reversed!
	hier.reverse.ClearAll();

	// Our shapes are now organized for patch-making -- Let's do the sides!
	int polys = bShape.splineCount;
	int poly, knot;
	int levelVerts = 0, levelVecs = 0, levelPatches = 0, nverts = 0, nvecs = 0, npatches = 0;
	int TVlevels = levels + 1, levelTVerts = 0, ntverts = 0, ntpatches = 0;
	BOOL anyClosed = FALSE;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		if(spline->Closed())
			anyClosed = TRUE;
		levelVerts += spline->KnotCount();
		levelTVerts += (spline->Segments() + 1);
		levelVecs += (spline->Segments() * 2);
		levelPatches += spline->Segments();
		}
	nverts = levelVerts * (levels + 1);
	npatches = levelPatches * levels;
	nvecs = (levelVecs * (levels + 1)) + levels * levelVerts * 2 + npatches * 4;
	if(texturing) {
		ntverts = levelTVerts * TVlevels;
		ntpatches = npatches;
		}

	pmesh.setNumVerts(nverts);
	pmesh.setNumVecs(nvecs);
	pmesh.setNumPatches(npatches);
	pmesh.setNumTVerts(ntverts);
	pmesh.setNumTVPatches(ntpatches);

	// Create the vertices!
	int vert = 0;
	int level;
	Point3 offset1, offset2;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int knots = spline->KnotCount();
		for(level = 0; level <= levels; ++level) {
			Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			if(level == 0)
				offset1 = offset;
			else
			if(level == levels)
				offset2 = offset;
			for(knot = 0; knot < knots; ++knot) {
				Point3 p = spline->GetKnotPoint(knot);
				pmesh.setVert(vert++, p + offset);
				}
			}
		}
	assert(vert == nverts);

    BOOL usePhysUVs = GetUsePhysicalScaleUVs();
	// Maybe create the texture vertices
	if(texturing) {
		int tvert = 0;
		int level;
		for(poly = 0; poly < polys; ++poly) {
			Spline3D *spline = bShape.splines[poly];
			if(!spline->KnotCount())
				continue;
			// Make it a polyline
			PolyLine pline;
			spline->MakePolyLine(pline, 10);
			int knots = spline->KnotCount();
			for(level = 0; level < TVlevels; ++level) {
				float tV = (float)level / (float)(TVlevels - 1);
                float vScale = usePhysUVs ? amount : 1.0f;
				int lverts = pline.numPts;
				int tp = 0;
				int texPts = spline->Segments() + 1;
				float cumLen = 0.0f;
				float totLen = pline.CurveLength();
                float uScale = usePhysUVs ? totLen : 1.0f;
				Point3 prevPt = pline.pts[0].p;
				int plix = 0;
				while(tp < texPts) {
					Point3 &pt = pline[plix].p;
					cumLen += Length(pt - prevPt);
					prevPt = pt;
					if(pline[plix].flags & POLYPT_KNOT) {
						float tU;
						if(tp == (texPts - 1))
							tU = 1.0f;
						else
							tU = cumLen / totLen;
						pmesh.setTVert(tvert++, UVVert(uScale*tU, vScale*tV, 0.0f));
						tp++;
						}
					plix = (plix + 1) % pline.numPts;
					}
				}
			}
		assert(tvert == ntverts);
		}

	// Create the vectors!
	int seg;
	int vec = 0;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int segs = spline->Segments();
		int knots = spline->KnotCount();
		// First, the vectors on each level
		for(level = 0; level <= levels; ++level) {
			Point3 offset = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			for(seg = 0; seg < segs; ++seg) {
				int seg2 = (seg + 1) % knots;
				if(spline->GetLineType(seg) == LTYPE_CURVE) {
					Point3 p = spline->GetOutVec(seg);
					pmesh.setVec(vec++, p + offset);
					p = spline->GetInVec(seg2);
					pmesh.setVec(vec++, p + offset);
					}
				else {
					Point3 p = spline->InterpBezier3D(seg, 0.333333f);
					pmesh.setVec(vec++, p + offset);
					p = spline->InterpBezier3D(seg, 0.666666f);
					pmesh.setVec(vec++, p + offset);
					}
				}
			}
		// Now, the vectors between the levels
		int baseVec = vec;
		for(level = 0; level < levels; ++level) {
			Point3 offsetA = Point3(0.0f, 0.0f, baseZ + (float)level / (float)levels * zSize);
			Point3 offsetB = Point3(0.0f, 0.0f, baseZ + (float)(level + 1) / (float)levels * zSize);
			Point3 offset1 = offsetA + (offsetB - offsetA) * 0.333333333f;
			Point3 offset2 = offsetA + (offsetB - offsetA) * 0.666666666f;
			for(knot = 0; knot < knots; ++knot) {
				Point3 p = spline->GetKnotPoint(knot);
				pmesh.setVec(vec++, p + offset1);
				pmesh.setVec(vec++, p + offset2);
				}
			}
		}

	// Create the patches!
	int np = 0;
	int baseVert = 0;
	int baseVec = 0;
	for(poly = 0; poly < polys; ++poly) {
		Spline3D *spline = bShape.splines[poly];
		if(!spline->KnotCount())
			continue;
		int knots = spline->KnotCount();
		int segs = spline->Segments();
		int baseVec1 = baseVec;	// Base vector index for this level
		int baseVec2 = baseVec + segs * 2 * (levels + 1);	// Base vector index for between levels
		for(level = 0; level < levels; ++level) {
			int sm = 0;
			BOOL firstSmooth = (spline->GetLineType(0) == LTYPE_CURVE && spline->GetLineType(segs-1) == LTYPE_CURVE && (spline->GetKnotType(0) == KTYPE_AUTO || spline->GetKnotType(0) == KTYPE_BEZIER)) ? TRUE : FALSE;
			for(seg = 0; seg < segs; ++seg, vec += 4) {
				int prevseg = (seg + segs - 1) % segs;
				int seg2 = (seg + 1) % knots;
				int a,b,c,d,ab,ba,bc,cb,cd,dc,da,ad;
				MtlID mtl = useShapeIDs ? spline->GetMatID(seg) : 2;
				a = baseVert + seg;
				b = baseVert + seg2;
				c = b + knots;
				d = a + knots;
				ab = baseVec1 + seg * 2;
				ba = ab + 1;
				bc = baseVec2 + seg2 * 2;
				cb = bc + 1;
				cd = ba + (segs * 2);
				dc = ab + (segs * 2);
				da = baseVec2 + seg * 2 + 1;
				ad = da - 1;
//DebugPrint(_T("Making patch %d: %d (%d %d) %d (%d %d) %d (%d %d) %d (%d %d)\n"),np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad);
				// If the vertex is not smooth, go to the next group!
				if(seg > 0 && !(spline->GetLineType(prevseg) == LTYPE_CURVE && spline->GetLineType(seg) == LTYPE_CURVE && (spline->GetKnotType(seg) == KTYPE_AUTO || spline->GetKnotType(seg) == KTYPE_BEZIER))) {
					sm++;
					if(sm > 2)
						sm = 1;
					}
				DWORD smoothGroup = 1 << sm;
				if(seg == segs - 1 && firstSmooth) {
					smoothGroup |= 1;
					}
				pmesh.MakeQuadPatch(np, a, ab, ba, b, bc, cb, c, cd, dc, d, da, ad, vec, vec+1, vec+2, vec+3, smooth ? smoothGroup : 0);
				pmesh.setPatchMtlIndex(np++, genMatIDs ? mtl : 0);
				}
			baseVert += knots;
			baseVec1 += (segs * 2);
			baseVec2 += (knots * 2);
			}
		baseVert += knots;
		baseVec += (segs * 2 * (levels + 1) + knots * 2 * levels);
		}
	assert(vec == nvecs);
	assert(np == npatches);

 	// Maybe create the texture patches!
	if(texturing) {
		int ntp = 0;
		int baseTVert = 0;
		for(poly = 0; poly < polys; ++poly) {
			Spline3D *spline = bShape.splines[poly];
			if(!spline->KnotCount())
				continue;
			int pknots = spline->Segments() + 1;
			int pverts = pknots * TVlevels;
			int segs = spline->Segments();
			for(level = 0; level < levels; ++level) {
				for(seg = 0; seg < segs; ++seg) {
					int prevseg = (seg + segs - 1) % segs;
					int seg2 = seg + 1;
					int a,b,c,d;
					a = baseTVert + seg;
					b = baseTVert + seg2;
					c = b + pknots;
					d = a + pknots;
					TVPatch &tp = pmesh.getTVPatch(ntp++);
					tp.setTVerts(a, b, c, d);
					
					}
				baseTVert += pknots;
				}
			baseTVert += pknots;
			}
		assert(ntp == ntpatches);
		}

	// If capping, do it!
	if(anyClosed && (capStart || capEnd)) {
		PatchCapInfo capInfo;
		bShape.MakeCap(t, capInfo);

		// Build information for capping
		PatchCapper capper(bShape);
		if(capStart) {
			vert = 0;
			int baseVec = 0;
			for(poly = 0; poly < polys; ++poly) {
				Spline3D *spline = bShape.splines[poly];
				if(!spline->KnotCount())
					continue;
				PatchCapPoly &capline = capper[poly];
				int lverts = spline->KnotCount();
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				vert += lverts * levels;
				vec = baseVec;
				int lvecs = spline->Segments() * 2;
				for(int v = 0; v < lvecs; ++v)
					capline.SetVec(v, vec++);			// Gives this vec's location in the mesh!
				baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2;
				}
			// Create a work matrix for capping
			Matrix3 mat = TransMatrix(offset1);
			int oldPatches = pmesh.numPatches;
			capper.CapPatchMesh(pmesh, capInfo, TRUE, 16, &mat, genMatIDs ? -1 : 0);
			// If texturing, create the texture patches and vertices
			if(texturing)
				MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs);
			}
		if(capEnd) {
			int baseVert = 0;
			int baseVec = 0;
			for(poly = 0; poly < polys; ++poly) {
				Spline3D *spline = bShape.splines[poly];
				if(!spline->KnotCount())
					continue;
				PatchCapPoly &capline = capper[poly];
				int lverts = spline->KnotCount();
				int vert = baseVert + lverts * levels;
				for(int v = 0; v < lverts; ++v)
					capline.SetVert(v, vert++);			// Gives this vert's location in the mesh!
				baseVert += lverts * (levels + 1);
				int lvecs = spline->Segments()*2;
				int vec = baseVec + lvecs * levels;
				for(int v = 0; v < lvecs; ++v)
					capline.SetVec(v, vec++);			// Gives this vec's location in the mesh!
				baseVec += lvecs * (levels + 1) + spline->KnotCount() * levels * 2;
				}
			// Create a work matrix for grid capping
			Matrix3 mat = TransMatrix(offset2);
			int oldPatches = pmesh.numPatches;
			capper.CapPatchMesh(pmesh, capInfo, FALSE, 16, &mat, genMatIDs ? -1 : 0);
			// If texturing, create the texture patches and vertices
			if(texturing)
				MakePatchCapTexture(pmesh, Inverse(mat), oldPatches, pmesh.numPatches, usePhysUVs);
			}
		}

	//watje new mapping
	if(texturing)
		{
		if (ver < 4)
			{
			for (int i = 0; i < pmesh.numPatches; i++)
				pmesh.patches[i].flags |= PATCH_LINEARMAPPING;
			}
		}


	// Ready the patch representation!
	if( !pmesh.buildLinkages() )
   {
      assert(0);
   }
	pmesh.computeInteriors();
	}