541 lines
14 KiB
C++
541 lines
14 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);
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void EditPatchMod::DoDeleteSelected()
|
|
{
|
|
switch (GetSubobjectLevel())
|
|
{
|
|
case EP_VERTEX:
|
|
DoVertDelete();
|
|
break;
|
|
case EP_EDGE:
|
|
DoEdgeDelete();
|
|
break;
|
|
case EP_PATCH:
|
|
DoPatchDelete();
|
|
break;
|
|
}
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
static void DeleteSelPatches(PatchMesh *patch, RPatchMesh *rpatch)
|
|
{
|
|
if (!patch->patchSel.NumberSet())
|
|
return; // Nothing to do!
|
|
|
|
int patches = patch->getNumPatches();
|
|
int verts = patch->getNumVerts();
|
|
|
|
// Tag the patches that are selected
|
|
BitArray delPatches(patches);
|
|
delPatches = patch->patchSel;
|
|
|
|
BitArray delVerts(verts);
|
|
delVerts.ClearAll();
|
|
|
|
DeletePatchParts(patch, rpatch, delVerts, delPatches);
|
|
patch->computeInteriors();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
BOOL PatchDeleteRecord::Redo(PatchMesh *patch, RPatchMesh *rpatch, int reRecord)
|
|
{
|
|
if (reRecord)
|
|
{
|
|
oldPatch = *patch;
|
|
roldPatch = *rpatch;
|
|
}
|
|
DeleteSelPatches(patch, rpatch);
|
|
return TRUE;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
void EditPatchMod::DoPatchDelete()
|
|
{
|
|
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();
|
|
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 bits are set in the selection set, let's DO IT!!
|
|
if (patch->patchSel.NumberSet())
|
|
{
|
|
altered = holdNeeded = 1;
|
|
if (theHold.Holding())
|
|
theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoPatchDelete"));
|
|
// Call the patch delete function
|
|
DeleteSelPatches(patch, rpatch);
|
|
patchData->UpdateChanges(patch, rpatch);
|
|
patchData->TempData(this)->Invalidate(PART_TOPO);
|
|
}
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
}
|
|
|
|
if (holdNeeded)
|
|
{
|
|
ResolveTopoChanges();
|
|
theHold.Accept(GetString(IDS_TH_PATCHDELETE));
|
|
}
|
|
else
|
|
{
|
|
ip->DisplayTempPrompt(GetString(IDS_TH_NOPATCHESSEL), PROMPT_TIME);
|
|
theHold.End();
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE);
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
void DeleteSelVerts(PatchMesh *patch, RPatchMesh *rpatch)
|
|
{
|
|
if (!patch->vertSel.NumberSet())
|
|
return; // Nothing to do!
|
|
|
|
int patches = patch->getNumPatches();
|
|
int verts = patch->getNumVerts();
|
|
|
|
// Tag the patches that use selected vertices
|
|
BitArray delPatches(patches);
|
|
delPatches.ClearAll();
|
|
for (int i = 0; i < patches; ++i)
|
|
{
|
|
Patch& p = patch->patches[i];
|
|
for (int j = 0; j < p.type; ++j)
|
|
{
|
|
if (patch->vertSel[p.v[j]])
|
|
{
|
|
delPatches.Set(i);
|
|
goto next_patch;
|
|
}
|
|
}
|
|
next_patch:;
|
|
}
|
|
|
|
BitArray delVerts(verts);
|
|
delVerts = patch->vertSel;
|
|
DeletePatchParts(patch, rpatch, delVerts, delPatches);
|
|
patch->computeInteriors();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Vertex Delete modifier method
|
|
void EditPatchMod::DoVertDelete()
|
|
{
|
|
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();
|
|
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 bits are set in the selection set, let's DO IT!!
|
|
if (patch->vertSel.NumberSet())
|
|
{
|
|
altered = holdNeeded = 1;
|
|
if (theHold.Holding())
|
|
theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoVertDelete"));
|
|
// Call the vertex delete function
|
|
DeleteSelVerts(patch, rpatch);
|
|
patchData->UpdateChanges(patch, rpatch);
|
|
patchData->TempData(this)->Invalidate(PART_TOPO);
|
|
}
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
}
|
|
|
|
if (holdNeeded)
|
|
{
|
|
ResolveTopoChanges();
|
|
theHold.Accept(GetString(IDS_TH_VERTDELETE));
|
|
}
|
|
else
|
|
{
|
|
ip->DisplayTempPrompt(GetString(IDS_TH_NOVERTSSEL), PROMPT_TIME);
|
|
theHold.End();
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE);
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Edger Delete modifier method
|
|
void EditPatchMod::DoEdgeDelete()
|
|
{
|
|
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();
|
|
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 bits are set in the selection set, let's DO IT!!
|
|
if (patch->edgeSel.NumberSet())
|
|
{
|
|
altered = holdNeeded = 1;
|
|
if (theHold.Holding())
|
|
theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "DoEdgeDelete"));
|
|
int edges = patch->getNumEdges();
|
|
int patches = patch->getNumPatches();
|
|
int verts = patch->getNumVerts();
|
|
|
|
// Tag the patches that are attached to selected edges
|
|
BitArray delPatches(patches);
|
|
delPatches.ClearAll();
|
|
|
|
for (int i = 0; i < edges; ++i)
|
|
{
|
|
if (patch->edgeSel[i])
|
|
{
|
|
#if (MAX_RELEASE < 4000)
|
|
if (patch->edges[i].patch1 >= 0)
|
|
delPatches.Set(patch->edges[i].patch1);
|
|
if (patch->edges[i].patch2 >= 0)
|
|
delPatches.Set(patch->edges[i].patch2);
|
|
#else // (MAX_RELEASE < 4000)
|
|
if (patch->edges[i].patches[0] >= 0)
|
|
delPatches.Set(patch->edges[i].patches[0]);
|
|
if (patch->edges[i].patches[1] >= 0)
|
|
delPatches.Set(patch->edges[i].patches[1]);
|
|
#endif // (MAX_RELEASE < 4000)
|
|
}
|
|
}
|
|
|
|
BitArray delVerts(verts);
|
|
delVerts.ClearAll();
|
|
|
|
DeletePatchParts(patch, rpatch, delVerts, delPatches);
|
|
patch->computeInteriors();
|
|
|
|
patchData->UpdateChanges(patch, rpatch);
|
|
patchData->TempData(this)->Invalidate(PART_TOPO);
|
|
}
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
}
|
|
|
|
if (holdNeeded)
|
|
{
|
|
ResolveTopoChanges();
|
|
theHold.Accept(GetString(IDS_TH_EDGEDELETE));
|
|
}
|
|
else
|
|
{
|
|
ip->DisplayTempPrompt(GetString(IDS_TH_NOEDGESSEL), PROMPT_TIME);
|
|
theHold.End();
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
NotifyDependents(FOREVER, PART_TOPO, REFMSG_CHANGE);
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
}
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
// Deletes any vertices tagged, also any patches tagged. Automatically deletes the vectors that
|
|
// are deleted as a result of the patch deletion and sweeps any vertices floating in space.
|
|
|
|
void DeletePatchParts(PatchMesh *patch, RPatchMesh *rpatch, BitArray &delVerts, BitArray &delPatches)
|
|
{
|
|
int patches = patch->getNumPatches();
|
|
int verts = patch->getNumVerts();
|
|
int vecs = patch->getNumVecs();
|
|
int dest;
|
|
|
|
// We treat vectors specially in order to clean up after welds. First, we tag 'em all,
|
|
// then untag only those on unselected patches so that any dangling vectors will be deleted.
|
|
BitArray delVectors(vecs);
|
|
delVectors.SetAll();
|
|
|
|
// Untag vectors that are on nondeleted patches
|
|
int i;
|
|
for (i = 0; i < patches; ++i)
|
|
{
|
|
if (!delPatches[i])
|
|
{
|
|
Patch& p = patch->patches[i];
|
|
int j;
|
|
for (j = 0; j <(p.type * 2); ++j)
|
|
{
|
|
delVectors.Clear(p.vec[j]);
|
|
}
|
|
for (j = 0; j < p.type; ++j)
|
|
delVectors.Clear(p.interior[j]);
|
|
}
|
|
}
|
|
|
|
// Make a table of vertices that are still in use -- Used to
|
|
// delete those vertices which are floating, unused, in space.
|
|
BitArray usedVerts(verts);
|
|
usedVerts.ClearAll();
|
|
for (i = 0; i < patches; ++i)
|
|
{
|
|
if (!delPatches[i])
|
|
{
|
|
Patch& p = patch->patches[i];
|
|
for (int j = 0; j < p.type; ++j)
|
|
{
|
|
usedVerts.Set(p.v[j]);
|
|
}
|
|
}
|
|
}
|
|
for (i = 0; i < verts; ++i)
|
|
{
|
|
if (!usedVerts[i])
|
|
delVerts.Set(i);
|
|
}
|
|
|
|
// If we have texture vertices, handle them, too
|
|
for (int chan = 0; chan < patch->getNumMaps(); ++chan)
|
|
{
|
|
int tverts = patch->numTVerts[chan];
|
|
if (tverts && patch->tvPatches[chan])
|
|
{
|
|
BitArray delTVerts(tverts);
|
|
delTVerts.SetAll();
|
|
for (i = 0; i < patches; ++i)
|
|
{
|
|
if (!delPatches[i])
|
|
{
|
|
Patch& p = patch->patches[i];
|
|
TVPatch& tp = patch->tvPatches[chan][i];
|
|
for (int j = 0; j < p.type; ++j)
|
|
delTVerts.Clear(tp.tv[j]);
|
|
}
|
|
}
|
|
// Got the list of tverts to delete -- now delete 'em
|
|
// Build a table of redirected texture vertex indices
|
|
int newTVerts = tverts - delTVerts.NumberSet();
|
|
IntTab tVertIndex;
|
|
tVertIndex.SetCount(tverts);
|
|
UVVert *newTVertArray = new UVVert[newTVerts];
|
|
dest = 0;
|
|
for (i = 0; i < tverts; ++i)
|
|
{
|
|
if (!delTVerts[i])
|
|
{
|
|
newTVertArray[dest] = patch->tVerts[chan][i];
|
|
tVertIndex[i] = dest++;
|
|
}
|
|
}
|
|
delete[] patch->tVerts[chan];
|
|
#if MAX_RELEASE <= 3100
|
|
patch->tVerts[chan] = newTVertArray;
|
|
#else
|
|
*(patch->tVerts[chan]) = *newTVertArray;
|
|
#endif
|
|
patch->numTVerts[chan] = newTVerts;
|
|
// Now, copy the untagged texture patches to a new array
|
|
// While you're at it, redirect the vertex indices
|
|
int newTVPatches = patches - delPatches.NumberSet();
|
|
TVPatch *newArray = new TVPatch[newTVPatches];
|
|
dest = 0;
|
|
for (i = 0; i < patches; ++i)
|
|
{
|
|
if (!delPatches[i])
|
|
{
|
|
Patch& p = patch->patches[i];
|
|
TVPatch& tp = newArray[dest++];
|
|
tp = patch->tvPatches[chan][i];
|
|
for (int j = 0; j < p.type; ++j)
|
|
tp.tv[j] = tVertIndex[tp.tv[j]];
|
|
}
|
|
}
|
|
delete[] patch->tvPatches[chan];
|
|
patch->tvPatches[chan] = newArray;;
|
|
}
|
|
}
|
|
|
|
// Build a table of redirected vector indices
|
|
IntTab vecIndex;
|
|
vecIndex.SetCount(vecs);
|
|
int newVectors = vecs - delVectors.NumberSet();
|
|
PatchVec *newVecArray = new PatchVec[newVectors];
|
|
dest = 0;
|
|
for (i = 0; i < vecs; ++i)
|
|
{
|
|
if (!delVectors[i])
|
|
{
|
|
newVecArray[dest] = patch->vecs[i];
|
|
vecIndex[i] = dest++;
|
|
}
|
|
else
|
|
vecIndex[i] = -1;
|
|
}
|
|
delete[] patch->vecs;
|
|
patch->vecs = newVecArray;
|
|
patch->numVecs = newVectors;
|
|
|
|
// Build a table of redirected vertex indices
|
|
int newVerts = verts - delVerts.NumberSet();
|
|
IntTab vertIndex;
|
|
vertIndex.SetCount(verts);
|
|
PatchVert *newVertArray = new PatchVert[newVerts];
|
|
BitArray newVertSel(newVerts);
|
|
newVertSel.ClearAll();
|
|
dest = 0;
|
|
for (i = 0; i < verts; ++i)
|
|
{
|
|
if (!delVerts[i])
|
|
{
|
|
newVertArray[dest] = patch->verts[i];
|
|
newVertSel.Set(dest, patch->vertSel[i]);
|
|
// redirect & adjust attached vector list
|
|
PatchVert& v = newVertArray[dest];
|
|
for (int j = 0; j < v.vectors.Count(); ++j)
|
|
{
|
|
v.vectors[j] = vecIndex[v.vectors[j]];
|
|
if (v.vectors[j] < 0)
|
|
{
|
|
v.vectors.Delete(j, 1);
|
|
j--; // realign index
|
|
}
|
|
}
|
|
vertIndex[i] = dest++;
|
|
}
|
|
}
|
|
delete[] patch->verts;
|
|
patch->verts = newVertArray;
|
|
patch->numVerts = newVerts;
|
|
patch->vertSel = newVertSel;
|
|
|
|
// Now, copy the untagged patches to a new array
|
|
// While you're at it, redirect the vertex and vector indices
|
|
int newPatches = patches - delPatches.NumberSet();
|
|
Patch *newArray = new Patch[newPatches];
|
|
BitArray newPatchSel(newPatches);
|
|
newPatchSel.ClearAll();
|
|
dest = 0;
|
|
for (i = 0; i < patches; ++i)
|
|
{
|
|
if (!delPatches[i])
|
|
{
|
|
newArray[dest] = patch->patches[i];
|
|
Patch& p = newArray[dest];
|
|
int j;
|
|
for (j = 0; j < p.type; ++j)
|
|
p.v[j] = vertIndex[p.v[j]];
|
|
for (j = 0; j <(p.type * 2); ++j)
|
|
p.vec[j] = vecIndex[p.vec[j]];
|
|
for (j = 0; j < p.type; ++j)
|
|
p.interior[j] = vecIndex[p.interior[j]];
|
|
newPatchSel.Set(dest++, patch->patchSel[i]);
|
|
}
|
|
}
|
|
|
|
// Rebuild info in rpatch
|
|
rpatch->DeleteAndSweep (delVerts, delPatches, *patch);
|
|
|
|
delete[] patch->patches;
|
|
patch->patches = newArray;;
|
|
patch->numPatches = newPatches;
|
|
patch->patchSel.SetSize(newPatches, TRUE);
|
|
patch->patchSel = newPatchSel;
|
|
patch->buildLinkages();
|
|
}
|
|
|