khanat-opennel-code/code/nel/tools/3d/plugin_max/nel_patch_edit/np_epm_detach.cpp

297 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);
}