298 lines
8.2 KiB
C++
298 lines
8.2 KiB
C++
|
#include "stdafx.h"
|
||
|
#include "editpat.h"
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
#define DBGWELD_DUMPx
|
||
|
#define DBGWELD_ACTIONx
|
||
|
#define DBG_NAMEDSELSx
|
||
|
|
||
|
#define PROMPT_TIME 2000
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
extern void DeletePatchParts(PatchMesh *patch, RPatchMesh *rpatch, BitArray &delVerts, BitArray &delPatches);
|
||
|
|
||
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
||
|
|
||
|
static TSTR detachName;
|
||
|
|
||
|
static BOOL CALLBACK DetachDialogProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
|
||
|
{
|
||
|
TCHAR tempName[256];
|
||
|
switch (message)
|
||
|
{
|
||
|
case WM_INITDIALOG:
|
||
|
SetDlgItemText(hDlg, IDC_DETACH_NAME, detachName);
|
||
|
SetFocus(GetDlgItem(hDlg, IDC_DETACH_NAME));
|
||
|
return FALSE;
|
||
|
case WM_COMMAND:
|
||
|
switch (LOWORD(wParam))
|
||
|
{
|
||
|
case IDOK:
|
||
|
GetDlgItemText(hDlg, IDC_DETACH_NAME, tempName, 255);
|
||
|
detachName = TSTR(tempName);
|
||
|
EndDialog(hDlg, 1);
|
||
|
return TRUE;
|
||
|
case IDCANCEL:
|
||
|
EndDialog(hDlg, 0);
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
|
||
|
static int GetDetachOptions(IObjParam *ip, TSTR& newName)
|
||
|
{
|
||
|
detachName = newName;
|
||
|
ip->MakeNameUnique(detachName);
|
||
|
if (DialogBox(hInstance, MAKEINTRESOURCE(IDD_DETACH), ip->GetMAXHWnd(), (DLGPROC)DetachDialogProc) == 1)
|
||
|
{
|
||
|
newName = detachName;
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
|
||
|
static void MakeDummyMapPatches(int channel, PatchMesh *patch)
|
||
|
{
|
||
|
patch->setNumMapVerts(channel, 1);
|
||
|
patch->tVerts[channel][0] = UVVert(0, 0, 0);
|
||
|
patch->setNumMapPatches(channel, patch->numPatches);
|
||
|
for (int i = 0; i < patch->numPatches; ++i)
|
||
|
{
|
||
|
Patch &p = patch->patches[i];
|
||
|
TVPatch &tp = patch->tvPatches[channel][i];
|
||
|
tp.Init(); // Sets all indices to zero
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
|
||
|
// Detach all selected patches
|
||
|
void EditPatchMod::DoPatchDetach(int copy, int reorient)
|
||
|
{
|
||
|
int dialoged = 0;
|
||
|
TSTR newName(GetString(IDS_TH_PATCH));
|
||
|
ModContextList mcList;
|
||
|
INodeTab nodes;
|
||
|
TimeValue t = ip->GetTime();
|
||
|
int holdNeeded = 0;
|
||
|
|
||
|
if (!ip)
|
||
|
return;
|
||
|
|
||
|
ip->GetModContexts(mcList, nodes);
|
||
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
||
|
|
||
|
theHold.Begin();
|
||
|
RecordTopologyTags();
|
||
|
|
||
|
// Create a patch mesh object
|
||
|
RPO *patchOb = new RPO;
|
||
|
patchOb->rpatch = new RPatchMesh;
|
||
|
PatchMesh &pmesh = patchOb->patch;
|
||
|
RPatchMesh &prmesh = *patchOb->rpatch;
|
||
|
int verts = 0;
|
||
|
int vecs = 0;
|
||
|
int patches = 0;
|
||
|
|
||
|
int multipleObjects =(mcList.Count() > 1) ? 1 : 0;
|
||
|
for (int i = 0; i < mcList.Count(); i++)
|
||
|
{
|
||
|
int altered = 0;
|
||
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
||
|
if (!patchData)
|
||
|
continue;
|
||
|
if (patchData->GetFlag(EPD_BEENDONE))
|
||
|
continue;
|
||
|
|
||
|
// If the mesh isn't yet cache, this will cause it to get cached.
|
||
|
RPatchMesh *rpatch;
|
||
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(t, rpatch);
|
||
|
if (!patch)
|
||
|
continue;
|
||
|
patchData->RecordTopologyTags(patch);
|
||
|
|
||
|
// If this is the first edit, then the delta arrays will be allocated
|
||
|
patchData->BeginEdit(t);
|
||
|
|
||
|
// If any patches selected, we'll need to process this one
|
||
|
if (patch->patchSel.NumberSet())
|
||
|
{
|
||
|
if (!dialoged)
|
||
|
{
|
||
|
dialoged = 1;
|
||
|
if (!GetDetachOptions(ip, newName))
|
||
|
goto bail_out;
|
||
|
}
|
||
|
// Save the unmodified info.
|
||
|
if (theHold.Holding())
|
||
|
{
|
||
|
theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoPatchDetach"));
|
||
|
}
|
||
|
PatchMesh wpatch = *patch;
|
||
|
RPatchMesh wrpatch = *rpatch;
|
||
|
BitArray vdel(wpatch.numVerts);
|
||
|
vdel.ClearAll();
|
||
|
BitArray pdel = wpatch.patchSel; // Get inverse selection set
|
||
|
// If not copying, delete the patches from this object
|
||
|
if (!copy)
|
||
|
DeletePatchParts(patch, rpatch, vdel, pdel);
|
||
|
pdel = ~wpatch.patchSel; // Get inverse selection set
|
||
|
if (pdel.NumberSet())
|
||
|
{
|
||
|
vdel.ClearAll();
|
||
|
DeletePatchParts(&wpatch, &wrpatch, vdel, pdel);
|
||
|
}
|
||
|
|
||
|
// RPatchMesh validity
|
||
|
wrpatch.Validity (wpatch, true);
|
||
|
|
||
|
// We've deleted everything that wasn't selected -- Now add this to the patch object accumulator
|
||
|
int oldVerts = pmesh.numVerts;
|
||
|
int oldVecs = pmesh.numVecs;
|
||
|
int oldPatches = pmesh.numPatches;
|
||
|
int newVerts = oldVerts + wpatch.numVerts;
|
||
|
int newVecs = oldVecs + wpatch.numVecs;
|
||
|
int newPatches = oldPatches + wpatch.numPatches;
|
||
|
pmesh.setNumVerts(newVerts, TRUE);
|
||
|
pmesh.setNumVecs(newVecs, TRUE);
|
||
|
pmesh.setNumPatches(newPatches, TRUE);
|
||
|
prmesh.SetNumVerts (newVerts);
|
||
|
prmesh.SetNumPatches (newPatches);
|
||
|
altered = holdNeeded = 1;
|
||
|
Matrix3 tm(1);
|
||
|
if (multipleObjects && !reorient)
|
||
|
tm = nodes[i]->GetObjectTM(t);
|
||
|
int i, i2;
|
||
|
for (i = 0, i2 = oldVerts; i < wpatch.numVerts; ++i, ++i2)
|
||
|
{
|
||
|
pmesh.verts[i2] = wpatch.verts[i];
|
||
|
pmesh.verts[i2].p = pmesh.verts[i2].p * tm;
|
||
|
|
||
|
// Copy rpatch info
|
||
|
prmesh.getUIVertex (i2)=wrpatch.getUIVertex (i);
|
||
|
}
|
||
|
for (i = 0, i2 = oldVecs; i < wpatch.numVecs; ++i, ++i2)
|
||
|
{
|
||
|
pmesh.vecs[i2] = wpatch.vecs[i];
|
||
|
pmesh.vecs[i2].p = pmesh.vecs[i2].p * tm;
|
||
|
}
|
||
|
for (i = 0, i2 = oldPatches; i < wpatch.numPatches; ++i, ++i2)
|
||
|
{
|
||
|
Patch &p = wpatch.patches[i];
|
||
|
Patch &p2 = pmesh.patches[i2];
|
||
|
p2 = p;
|
||
|
int j;
|
||
|
for (j = 0; j < p2.type; ++j)
|
||
|
{
|
||
|
// Adjust vertices and interior vectors
|
||
|
p2.v[j] += oldVerts;
|
||
|
p2.interior[j] += oldVecs;
|
||
|
}
|
||
|
for (j = 0; j <(p2.type * 2); ++j) // Adjust edge vectors
|
||
|
p2.vec[j] += oldVecs;
|
||
|
|
||
|
// Copy rpatch info
|
||
|
prmesh.getUIPatch (i2)=wrpatch.getUIPatch (i);
|
||
|
}
|
||
|
// Now copy over mapping information
|
||
|
int dmaps = pmesh.getNumMaps();
|
||
|
int smaps = wpatch.getNumMaps();
|
||
|
int maxMaps = dmaps > smaps ? dmaps : smaps;
|
||
|
if (maxMaps != dmaps)
|
||
|
pmesh.setNumMaps(maxMaps, TRUE);
|
||
|
if (maxMaps != smaps)
|
||
|
wpatch.setNumMaps(maxMaps, TRUE);
|
||
|
// Then make sure any active maps are active in both:
|
||
|
int chan;
|
||
|
for (chan = 0; chan < maxMaps; ++chan)
|
||
|
{
|
||
|
if (pmesh.tvPatches[chan] || wpatch.tvPatches[chan])
|
||
|
{
|
||
|
if (!pmesh.tvPatches[chan])
|
||
|
MakeDummyMapPatches(chan, &pmesh);
|
||
|
if (!wpatch.tvPatches[chan])
|
||
|
MakeDummyMapPatches(chan, &wpatch);
|
||
|
}
|
||
|
}
|
||
|
for (chan = 0; chan < pmesh.getNumMaps(); ++chan)
|
||
|
{
|
||
|
if (chan < wpatch.getNumMaps())
|
||
|
{
|
||
|
int oldTVerts = pmesh.numTVerts[chan];
|
||
|
int newTVerts = oldTVerts + wpatch.numTVerts[chan];
|
||
|
pmesh.setNumMapVerts(chan, newTVerts, TRUE);
|
||
|
for (i = 0, i2 = oldTVerts; i < wpatch.numTVerts[chan]; ++i, ++i2)
|
||
|
pmesh.tVerts[chan][i2] = wpatch.tVerts[chan][i];
|
||
|
if (pmesh.tvPatches[chan])
|
||
|
{
|
||
|
for (i = 0, i2 = oldPatches; i < wpatch.numPatches; ++i, ++i2)
|
||
|
{
|
||
|
Patch &p = wpatch.patches[i];
|
||
|
TVPatch &tp = wpatch.tvPatches[chan][i];
|
||
|
TVPatch &tp2 = pmesh.tvPatches[chan][i2];
|
||
|
tp2 = tp;
|
||
|
for (int j = 0; j < p.type; ++j) // Adjust vertices
|
||
|
tp2.tv[j] += oldTVerts;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
patchData->UpdateChanges(patch, rpatch);
|
||
|
patchData->TempData(this)->Invalidate(PART_TOPO);
|
||
|
}
|
||
|
|
||
|
bail_out:
|
||
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
||
|
}
|
||
|
|
||
|
if (holdNeeded)
|
||
|
{
|
||
|
pmesh.computeInteriors();
|
||
|
pmesh.buildLinkages();
|
||
|
INode *newNode = ip->CreateObjectNode(patchOb);
|
||
|
newNode->SetMtl(nodes[0]->GetMtl());
|
||
|
newNode->SetName(newName.data());
|
||
|
patchOb->patch.InvalidateGeomCache();
|
||
|
if (!multipleObjects)
|
||
|
{
|
||
|
// Single input object?
|
||
|
if (!reorient)
|
||
|
{
|
||
|
Matrix3 tm = nodes[0]->GetObjectTM(t);
|
||
|
newNode->SetNodeTM(t, tm); // Use this object's TM.
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (!reorient)
|
||
|
{
|
||
|
Matrix3 matrix;
|
||
|
matrix.IdentityMatrix();
|
||
|
newNode->SetNodeTM(t, matrix); // Use identity TM
|
||
|
}
|
||
|
}
|
||
|
newNode->FlagForeground(t); // WORKAROUND!
|
||
|
ResolveTopoChanges();
|
||
|
theHold.Accept(GetString(IDS_TH_DETACHPATCH));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete patchOb; // Didn't need it after all!
|
||
|
if (!dialoged)
|
||
|
ip->DisplayTempPrompt(GetString(IDS_TH_NOPATCHESSEL), PROMPT_TIME);
|
||
|
theHold.End();
|
||
|
}
|
||
|
|
||
|
nodes.DisposeTemporary();
|
||
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
||
|
NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE);
|
||
|
ip->RedrawViews(t, REDRAW_NORMAL);
|
||
|
}
|