2012-05-29 13:31:11 +00:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include "editpat.h"
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#define DBGWELD_DUMPx
|
|
|
|
#define DBGWELD_ACTIONx
|
|
|
|
#define DBG_NAMEDSELSx
|
|
|
|
|
|
|
|
#define PROMPT_TIME 2000
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
class EPSelSetNameRestore : public RestoreObj
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
TSTR undo, redo;
|
|
|
|
TSTR *target;
|
|
|
|
EditPatchMod *mod;
|
|
|
|
EPSelSetNameRestore(EditPatchMod *m, TSTR *t, TSTR &newName)
|
|
|
|
{
|
|
|
|
mod = m;
|
|
|
|
undo = *t;
|
|
|
|
target = t;
|
|
|
|
}
|
|
|
|
void Restore(int isUndo)
|
|
|
|
{
|
|
|
|
if (isUndo)
|
|
|
|
redo = *target;
|
|
|
|
*target = undo;
|
|
|
|
if (mod->ip)
|
|
|
|
mod->ip->NamedSelSetListChanged();
|
|
|
|
}
|
|
|
|
void Redo()
|
|
|
|
{
|
|
|
|
*target = redo;
|
|
|
|
if (mod->ip)
|
|
|
|
mod->ip->NamedSelSetListChanged();
|
|
|
|
}
|
|
|
|
|
|
|
|
TSTR Description() {return TSTR(_T("Sel Set Name"));}
|
|
|
|
};
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
extern int attachReorient;
|
|
|
|
extern Point3 zeroPoint;
|
|
|
|
extern BOOL filterVerts;
|
|
|
|
extern int lockedHandles;
|
|
|
|
|
|
|
|
extern void ChangePatchType(PatchMesh *patch, int index, int type);
|
|
|
|
|
|
|
|
HWND EditPatchMod::hSelectPanel = NULL;
|
|
|
|
HWND EditPatchMod::hOpsPanel = NULL;
|
|
|
|
HWND EditPatchMod::hSurfPanel = NULL;
|
|
|
|
HWND EditPatchMod::hTilePanel = NULL;
|
|
|
|
HWND EditPatchMod::hEdgePanel = NULL;
|
|
|
|
BOOL EditPatchMod::rsSel = TRUE;
|
|
|
|
BOOL EditPatchMod::rsOps = TRUE;
|
|
|
|
BOOL EditPatchMod::rsSurf = TRUE;
|
|
|
|
BOOL EditPatchMod::rsTile = TRUE;
|
|
|
|
BOOL EditPatchMod::rsEdge = TRUE;
|
|
|
|
IObjParam* EditPatchMod::ip = NULL;
|
|
|
|
MoveModBoxCMode* EditPatchMod::moveMode = NULL;
|
|
|
|
RotateModBoxCMode* EditPatchMod::rotMode = NULL;
|
|
|
|
UScaleModBoxCMode* EditPatchMod::uscaleMode = NULL;
|
|
|
|
NUScaleModBoxCMode* EditPatchMod::nuscaleMode = NULL;
|
|
|
|
SquashModBoxCMode * EditPatchMod::squashMode = NULL;
|
|
|
|
SelectModBoxCMode* EditPatchMod::selectMode = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::weldSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::stepsSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::tileSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::transitionSpin = NULL;
|
|
|
|
|
|
|
|
// 3-18-99 to suport render steps and removal of the mental tesselator
|
|
|
|
ISpinnerControl* EditPatchMod::stepsRenderSpin = NULL;
|
|
|
|
|
|
|
|
BOOL EditPatchMod::settingViewportTess = FALSE;
|
|
|
|
BOOL EditPatchMod::settingDisp = FALSE;
|
|
|
|
ISpinnerControl* EditPatchMod::uSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::vSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::edgeSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::distSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::angSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::mergeSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::matSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::tessUSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::tessVSpin = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::tileNum = NULL;
|
|
|
|
ISpinnerControl* EditPatchMod::tileRot = NULL;
|
|
|
|
BOOL EditPatchMod::patchUIValid = TRUE;
|
|
|
|
BOOL EditPatchMod::tileUIValid = TRUE;
|
|
|
|
BOOL EditPatchMod::edgeUIValid = TRUE;
|
|
|
|
PickPatchAttach EditPatchMod::pickCB;
|
|
|
|
int EditPatchMod::condenseMat = FALSE;
|
|
|
|
int EditPatchMod::attachMat = ATTACHMAT_IDTOMAT;
|
|
|
|
int EditPatchMod::channelModified = EDITPAT_CHANNELS;
|
|
|
|
|
|
|
|
EPM_BindCMode* EditPatchMod::bindMode = NULL;
|
|
|
|
EPM_ExtrudeCMode* EditPatchMod::extrudeMode = NULL;
|
|
|
|
EPM_BevelCMode* EditPatchMod::bevelMode = NULL;
|
|
|
|
int EditPatchMod::CurrentTileSet = -1;
|
|
|
|
int EditPatchMod::brushSize = 0; // Default 1 tile
|
|
|
|
int EditPatchMod::ColorBushSize = 0;
|
|
|
|
int EditPatchMod::tileSize = 1; // Default 256
|
|
|
|
bool EditPatchMod::additiveTile = false; //
|
|
|
|
int EditPatchMod::TileGroup=0; // Default all tiles
|
|
|
|
int EditPatchMod::DisplaceTile=0; // Default displace 0
|
|
|
|
int EditPatchMod::DisplaceTileSet=-1; //
|
|
|
|
uint EditPatchMod::TileFillRotation=0;
|
|
|
|
bool EditPatchMod::TileTrick=false;
|
|
|
|
bool EditPatchMod::automaticLighting=false;
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
//--- Named Selection Set Methods ------------------------------------
|
|
|
|
|
|
|
|
// Used by EditPatchMod destructor to free pointers
|
|
|
|
void EditPatchMod::ClearSetNames()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < namedSel[i].Count(); j++)
|
|
|
|
{
|
|
|
|
delete namedSel[i][j];
|
|
|
|
namedSel[i][j] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int EditPatchMod::FindSet(TSTR &setName, int level)
|
|
|
|
{
|
|
|
|
nlassert(level>0 && level < 4);
|
|
|
|
for (int i = 0; i < namedSel[level - 1].Count(); i++)
|
|
|
|
{
|
|
|
|
if (setName == *namedSel[level - 1][i])
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::AddSet(TSTR &setName, int level)
|
|
|
|
{
|
|
|
|
nlassert(level>0 && level < 4);
|
|
|
|
TSTR *name = new TSTR(setName);
|
|
|
|
namedSel[level - 1].Append(1, &name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::RemoveSet(TSTR &setName, int level)
|
|
|
|
{
|
|
|
|
MaybeFixupNamedSels();
|
|
|
|
nlassert(level>0 && level < 4);
|
|
|
|
int i = FindSet(setName, level);
|
|
|
|
if (i >= 0)
|
|
|
|
{
|
|
|
|
delete namedSel[level - 1][i];
|
|
|
|
namedSel[level - 1].Delete(i, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void EditPatchMod::SetupNamedSelDropDown()
|
|
|
|
{
|
|
|
|
// Setup named selection sets
|
|
|
|
if (selLevel == EP_OBJECT)
|
|
|
|
return;
|
|
|
|
ip->ClearSubObjectNamedSelSets();
|
|
|
|
for (int i = 0; i < namedSel[selLevel - 1].Count(); i++)
|
|
|
|
ip->AppendSubObjectNamedSelSet(*namedSel[selLevel - 1][i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
int EditPatchMod::NumNamedSelSets()
|
|
|
|
{
|
|
|
|
if (GetSubobjectLevel() == PO_OBJECT)
|
|
|
|
return 0;
|
|
|
|
if (GetSubobjectLevel() == PO_TILE)
|
|
|
|
return 0;
|
|
|
|
return namedSel[selLevel - 1].Count();
|
|
|
|
}
|
|
|
|
|
|
|
|
TSTR EditPatchMod::GetNamedSelSetName(int i)
|
|
|
|
{
|
|
|
|
return *namedSel[selLevel - 1][i];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditPatchMod::SetNamedSelSetName(int index, TSTR &newName)
|
|
|
|
{
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
MaybeFixupNamedSels();
|
|
|
|
|
|
|
|
// First do the master name list
|
|
|
|
if (theHold.Holding())
|
|
|
|
theHold.Put(new EPSelSetNameRestore(this, namedSel[selLevel - 1][index], newName));
|
|
|
|
|
|
|
|
// Save the old name so we can change those in the EditPatchData
|
|
|
|
TSTR oldName = *namedSel[selLevel - 1][index];
|
|
|
|
*namedSel[selLevel - 1][index] = newName;
|
|
|
|
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (patchData)
|
|
|
|
patchData->GetSelSet(this).RenameSet(oldName, newName);
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::NewSetByOperator(TSTR &newName, Tab < int> &sets, int op)
|
|
|
|
{
|
|
|
|
MaybeFixupNamedSels();
|
|
|
|
|
|
|
|
// First do it in the master name list
|
|
|
|
AddSet(newName, selLevel);
|
|
|
|
// TO DO: Undo?
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
GenericNamedSelSetList &set = patchData->GetSelSet(this);
|
|
|
|
BitArray bits = *set.GetSetByIndex(sets[0]);
|
|
|
|
for (i = 1; i < sets.Count(); i++)
|
|
|
|
{
|
|
|
|
BitArray *bit2 = set.GetSetByIndex(sets[i]);
|
|
|
|
switch (op)
|
|
|
|
{
|
|
|
|
case NEWSET_MERGE:
|
|
|
|
bits |= *bit2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NEWSET_INTERSECTION:
|
|
|
|
bits &= *bit2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case NEWSET_SUBTRACT:
|
|
|
|
bits &= ~(*bit2);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
set.AppendSet(bits, 0, newName);
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// Named selection set copy/paste methods follow...
|
|
|
|
|
|
|
|
static BOOL CALLBACK PickSetNameDlgProc(
|
|
|
|
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
static TSTR *name;
|
|
|
|
|
|
|
|
switch (msg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
{
|
|
|
|
name =(TSTR*)lParam;
|
|
|
|
ICustEdit *edit =GetICustEdit(GetDlgItem(hWnd, IDC_SET_NAME));
|
|
|
|
edit->SetText(*name);
|
|
|
|
ReleaseICustEdit(edit);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
|
|
|
case IDOK:
|
|
|
|
{
|
|
|
|
ICustEdit *edit =GetICustEdit(GetDlgItem(hWnd, IDC_SET_NAME));
|
|
|
|
TCHAR buf[256];
|
|
|
|
edit->GetText(buf, 256);
|
|
|
|
*name = TSTR(buf);
|
|
|
|
ReleaseICustEdit(edit);
|
|
|
|
EndDialog(hWnd, 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hWnd, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
};
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOL EditPatchMod::GetUniqueSetName(TSTR &name)
|
|
|
|
{
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if (FindSet(name, selLevel) < 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (!DialogBoxParam(
|
|
|
|
hInstance,
|
|
|
|
MAKEINTRESOURCE(IDD_PASTE_NAMEDSET),
|
|
|
|
ip->GetMAXHWnd(),
|
|
|
|
PickSetNameDlgProc,
|
|
|
|
(LPARAM)&name))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL CALLBACK PickSetDlgProc(
|
|
|
|
HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
switch (msg)
|
|
|
|
{
|
|
|
|
case WM_INITDIALOG:
|
|
|
|
{
|
|
|
|
Tab<TSTR*> &names = *((Tab < TSTR*>*)lParam);
|
|
|
|
for (int i = 0; i < names.Count(); i++)
|
|
|
|
{
|
|
|
|
int pos = SendDlgItemMessage(hWnd, IDC_NS_LIST, LB_ADDSTRING, 0,
|
|
|
|
(LPARAM)(TCHAR*)*names[i]);
|
|
|
|
SendDlgItemMessage(hWnd, IDC_NS_LIST, LB_SETITEMDATA, pos, i);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case WM_COMMAND:
|
|
|
|
switch (LOWORD(wParam))
|
|
|
|
{
|
|
|
|
case IDC_NS_LIST:
|
|
|
|
if (HIWORD(wParam) != LBN_DBLCLK)
|
|
|
|
break;
|
|
|
|
// fall through
|
|
|
|
case IDOK:
|
|
|
|
{
|
|
|
|
int sel = SendDlgItemMessage(hWnd, IDC_NS_LIST, LB_GETCURSEL, 0, 0);
|
|
|
|
if (sel != LB_ERR)
|
|
|
|
{
|
|
|
|
int res =SendDlgItemMessage(hWnd, IDC_NS_LIST, LB_GETITEMDATA, sel, 0);
|
|
|
|
EndDialog(hWnd, res);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
|
|
|
|
case IDCANCEL:
|
|
|
|
EndDialog(hWnd, - 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return FALSE;
|
|
|
|
};
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
int EditPatchMod::SelectNamedSet()
|
|
|
|
{
|
|
|
|
Tab < TSTR*> names = namedSel[selLevel - 1];
|
|
|
|
return DialogBoxParam(
|
|
|
|
hInstance,
|
|
|
|
MAKEINTRESOURCE(IDD_SEL_NAMEDSET),
|
|
|
|
ip->GetMAXHWnd(),
|
|
|
|
PickSetDlgProc,
|
|
|
|
(LPARAM)&names);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::NSCopy()
|
|
|
|
{
|
|
|
|
MaybeFixupNamedSels();
|
|
|
|
if (selLevel == EP_OBJECT)
|
|
|
|
return;
|
|
|
|
int index = SelectNamedSet();
|
|
|
|
if (index < 0)
|
|
|
|
return;
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
// Get the name for that index
|
|
|
|
int nsl = namedSetLevel[selLevel];
|
|
|
|
TSTR setName = *namedSel[nsl][index];
|
|
|
|
PatchNamedSelClip *clip = new PatchNamedSelClip(setName);
|
|
|
|
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GenericNamedSelSetList &setList = patchData->GetSelSet(this);
|
|
|
|
BitArray *set = setList.GetSet(setName);
|
|
|
|
if (set)
|
|
|
|
{
|
|
|
|
BitArray *bits = new BitArray(*set);
|
|
|
|
clip->sets.Append(1, &bits);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SetPatchNamedSelClip(clip, namedClipLevel[selLevel]);
|
|
|
|
|
|
|
|
// Enable the paste button
|
|
|
|
ICustButton *but = GetICustButton(GetDlgItem(hSelectPanel, IDC_NS_PASTE));
|
|
|
|
but->Enable();
|
|
|
|
ReleaseICustButton(but);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::NSPaste()
|
|
|
|
{
|
|
|
|
MaybeFixupNamedSels();
|
|
|
|
if (selLevel == EP_OBJECT)
|
|
|
|
return;
|
|
|
|
int nsl = namedSetLevel[selLevel];
|
|
|
|
PatchNamedSelClip *clip = GetPatchNamedSelClip(namedClipLevel[selLevel]);
|
|
|
|
if (!clip)
|
|
|
|
return;
|
|
|
|
TSTR name = clip->name;
|
|
|
|
if (!GetUniqueSetName(name))
|
|
|
|
return;
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
AddSet(name, selLevel);
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
GenericNamedSelSetList & setList = patchData->GetSelSet(this);
|
|
|
|
|
|
|
|
if (i >= clip->sets.Count())
|
|
|
|
{
|
|
|
|
BitArray bits;
|
|
|
|
setList.AppendSet(bits, 0, name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
setList.AppendSet(*clip->sets[i], 0, name);
|
|
|
|
}
|
|
|
|
|
|
|
|
ActivateSubSelSet(name);
|
|
|
|
ip->SetCurNamedSelSet(name);
|
|
|
|
SetupNamedSelDropDown();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Old MAX files (pre-r3) have EditPatchData named selections without names assigned. This
|
|
|
|
// assigns them their proper names for r3 and later code. If no fixup is required, this does nothing.
|
|
|
|
void EditPatchMod::MaybeFixupNamedSels()
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Go thru the modifier contexts, and stuff the named selection names into the EditPatchData
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
#ifdef DBG_NAMEDSELS
|
|
|
|
DebugPrint("Context/named sels:\n");
|
|
|
|
for (i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Go thru each subobject level
|
|
|
|
for (int j = 0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
GenericNamedSelSetList &pdSel = patchData->GetSelSet(j);
|
|
|
|
for (int k = 0; k < pdSel.Count(); ++k)
|
|
|
|
DebugPrint("Context %d, level %d, set %d: [%s]\n", i, j, k, *pdSel.names[k]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif // DBG_NAMEDSELS
|
|
|
|
|
|
|
|
if (!namedSelNeedsFixup)
|
|
|
|
{
|
|
|
|
#ifdef DBG_NAMEDSELS
|
|
|
|
DebugPrint("!!! NO FIXUP REQUIRED !!!\n");
|
|
|
|
#endif // DBG_NAMEDSELS
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DBG_NAMEDSELS
|
|
|
|
DebugPrint("*** Fixing up named sels ***\n");
|
|
|
|
#endif // DBG_NAMEDSELS
|
|
|
|
|
|
|
|
for (i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
// Go thru each subobject level
|
|
|
|
for (int j = 0; j < 3; ++j)
|
|
|
|
{
|
|
|
|
Tab < TSTR*> &mSel = namedSel[j];
|
|
|
|
GenericNamedSelSetList &pdSel = patchData->GetSelSet(j);
|
|
|
|
// Some old files may have improper counts in the EditPatchData. Limit the counter
|
|
|
|
int mc = mSel.Count();
|
|
|
|
int pdc = pdSel.Count();
|
|
|
|
int limit =(mc < pdc) ? mc : pdc;
|
|
|
|
#ifdef DBG_NAMEDSELS
|
|
|
|
if (mc != pdc)
|
|
|
|
DebugPrint("****** mSel.Count=%d, pdSel.Count=%d ******\n", mc, pdc);
|
|
|
|
#endif // DBG_NAMEDSELS
|
|
|
|
for (int k = 0; k < limit; ++k)
|
|
|
|
*pdSel.names[k] = *mSel[k];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
namedSelNeedsFixup = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::RemoveAllSets()
|
|
|
|
{
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
int j;
|
|
|
|
for (j = patchData->vselSet.Count() - 1; j >= 0; j--)
|
|
|
|
{
|
|
|
|
patchData->vselSet.DeleteSet(j);
|
|
|
|
}
|
|
|
|
for (j = patchData->pselSet.Count() - 1; j >= 0; j--)
|
|
|
|
{
|
|
|
|
patchData->pselSet.DeleteSet(j);
|
|
|
|
}
|
|
|
|
for (j = patchData->eselSet.Count() - 1; j >= 0; j--)
|
|
|
|
{
|
|
|
|
patchData->eselSet.DeleteSet(j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 0; j < 3; j++)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < namedSel[j].Count(); i++)
|
|
|
|
{
|
|
|
|
delete namedSel[j][i];
|
|
|
|
}
|
|
|
|
namedSel[j].Resize(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
ip->ClearCurNamedSelSet();
|
|
|
|
ip->ClearSubObjectNamedSelSets();
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
}
|
|
|
|
|
|
|
|
Interval EditPatchMod::LocalValidity(TimeValue t)
|
|
|
|
{
|
|
|
|
// Force a cache if being edited.
|
|
|
|
if (TestAFlag(A_MOD_BEING_EDITED))
|
|
|
|
return NEVER;
|
|
|
|
return FOREVER;
|
|
|
|
}
|
|
|
|
|
|
|
|
RefTargetHandle EditPatchMod::Clone(RemapDir& remap)
|
|
|
|
{
|
|
|
|
EditPatchMod* newmod = new EditPatchMod();
|
|
|
|
newmod->selLevel = selLevel;
|
|
|
|
newmod->displaySurface = displaySurface;
|
|
|
|
newmod->displayLattice = displayLattice;
|
|
|
|
newmod->meshSteps = meshSteps;
|
|
|
|
// 3-18-99 to suport render steps and removal of the mental tesselator
|
|
|
|
newmod->meshStepsRender = meshStepsRender;
|
|
|
|
newmod->showInterior = showInterior;
|
|
|
|
|
|
|
|
// newmod->meshAdaptive = meshAdaptive; // Future use (Not used now)
|
|
|
|
newmod->transitionType = transitionType;
|
|
|
|
newmod->tileLevel = tileLevel;
|
|
|
|
newmod->tileMode = tileMode;
|
|
|
|
newmod->includeMeshes = includeMeshes;
|
|
|
|
newmod->keepMapping = keepMapping;
|
|
|
|
newmod->viewTess = viewTess;
|
|
|
|
newmod->prodTess = prodTess;
|
|
|
|
newmod->dispTess = dispTess;
|
|
|
|
newmod->mViewTessNormals = mViewTessNormals;
|
|
|
|
newmod->mProdTessNormals = mProdTessNormals;
|
|
|
|
newmod->mViewTessWeld = mViewTessWeld;
|
|
|
|
newmod->mProdTessWeld = mProdTessWeld;
|
|
|
|
newmod->propagate = propagate;
|
|
|
|
return (newmod);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::ClearPatchDataFlag(ModContextList& mcList, DWORD f)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
patchData->SetFlag(f, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::XFormHandles(XFormProc *xproc, TimeValue t, Matrix3& partm, Matrix3& tmAxis, int object, int handleIndex)
|
|
|
|
{
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
Matrix3 mat, imat, theMatrix;
|
|
|
|
Interval valid;
|
|
|
|
int numAxis;
|
|
|
|
Point3 oldpt, newpt, oldin, oldout, rel;
|
|
|
|
BOOL shiftPressed = FALSE;
|
|
|
|
static BOOL wasBroken;
|
|
|
|
Point3 theKnot;
|
|
|
|
Point3 oldVector;
|
|
|
|
Point3 newVector;
|
|
|
|
float oldLen;
|
|
|
|
float newLen;
|
|
|
|
// DebugPrint("XFormHandles\n");
|
|
|
|
shiftPressed =(GetKeyState(VK_SHIFT) & 0x8000) ? TRUE : FALSE;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
numAxis = ip->GetNumAxis();
|
|
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
|
|
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[object]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
{
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is the first edit, then the delta arrays will be allocated
|
|
|
|
patchData->BeginEdit(t);
|
|
|
|
|
|
|
|
// Create a change record for this object and store a pointer to its delta info in this EditPatchData
|
|
|
|
if (!TestAFlag(A_HELD))
|
|
|
|
{
|
|
|
|
patchData->vdelta.SetSize(*patch, FALSE);
|
|
|
|
if (theHold.Holding())
|
|
|
|
{
|
|
|
|
theHold.Put(new PatchRestore(patchData, this, patch, rpatch, "XFormHandles"));
|
|
|
|
}
|
|
|
|
patchData->vdelta.Zero(); // Reset all deltas
|
|
|
|
patchData->ClearHandleFlag();
|
|
|
|
wasBroken = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (wasBroken && !shiftPressed)
|
|
|
|
wasBroken = FALSE;
|
|
|
|
if (patchData->DoingHandles())
|
|
|
|
patchData->ApplyHandlesAndZero(*patch); // Reapply the slave handle deltas
|
|
|
|
else
|
|
|
|
patchData->vdelta.Zero();
|
|
|
|
}
|
|
|
|
|
|
|
|
patchData->SetHandleFlag(handleIndex);
|
|
|
|
int primaryKnot = patch->vecs[handleIndex].vert;
|
|
|
|
Point3Tab &pDeltas = patchData->vdelta.dtab.vtab;
|
|
|
|
|
|
|
|
tmAxis = ip->GetTransformAxis(nodes[object], primaryKnot);
|
|
|
|
mat = nodes[object]->GetObjectTM(t, &valid) * Inverse(tmAxis);
|
|
|
|
imat = Inverse(mat);
|
|
|
|
xproc->SetMat(mat);
|
|
|
|
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->vecs[handleIndex].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
|
|
|
|
// Update the vector being moved
|
|
|
|
patch->vecs[handleIndex].p = newpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.SetVec(handleIndex, newpt - oldpt);
|
|
|
|
|
|
|
|
if (primaryKnot >= 0)
|
|
|
|
{
|
|
|
|
PatchVert &vert = patch->verts[primaryKnot];
|
|
|
|
theKnot = vert.p;
|
|
|
|
// If locked handles, turn the movement into a transformation matrix
|
|
|
|
// and transform all the handles attached to the owner vertex
|
|
|
|
if (lockedHandles)
|
|
|
|
{
|
|
|
|
if (!wasBroken && shiftPressed)
|
|
|
|
wasBroken = TRUE;
|
|
|
|
goto locked_handles;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (shiftPressed)
|
|
|
|
{
|
|
|
|
wasBroken = TRUE;
|
|
|
|
vert.flags &= ~PVERT_COPLANAR;
|
|
|
|
// Need to record this for undo!
|
|
|
|
patchData->vdelta.SetVertType(primaryKnot, PVERT_COPLANAR);
|
|
|
|
}
|
|
|
|
// If a coplanar knot, do the other vectors!
|
|
|
|
// If at the same point as knot, do nothing!
|
|
|
|
if ((vert.flags & PVERT_COPLANAR) &&(vert.vectors.Count() > 2) && !(newpt == theKnot))
|
|
|
|
{
|
|
|
|
locked_handles:
|
|
|
|
oldVector = oldpt - theKnot;
|
|
|
|
newVector = newpt - theKnot;
|
|
|
|
oldLen = Length(oldVector);
|
|
|
|
newLen = Length(newVector);
|
|
|
|
Point3 oldNorm = Normalize(oldVector);
|
|
|
|
Point3 newNorm = Normalize(newVector);
|
|
|
|
theMatrix.IdentityMatrix();
|
|
|
|
Point3 axis;
|
|
|
|
float angle = 0.0f;
|
|
|
|
int owner = patch->vecs[handleIndex].vert;
|
|
|
|
if (owner >= 0)
|
|
|
|
{
|
|
|
|
PatchVert &vert = patch->verts[owner];
|
|
|
|
int vectors = vert.vectors.Count();
|
|
|
|
// Watch out for cases where the vectors are exactly opposite -- This
|
|
|
|
// results in an invalid axis for transformation!
|
|
|
|
// In this case, we look for a vector to one of the other handles that
|
|
|
|
// will give us a useful vector for the rotational axis
|
|
|
|
if (newNorm == -oldNorm)
|
|
|
|
{
|
|
|
|
for (int v = 0; v < vectors; ++v)
|
|
|
|
{
|
|
|
|
int theVec = vert.vectors[v];
|
|
|
|
// Ignore the vector being moved!
|
|
|
|
if (theVec != handleIndex)
|
|
|
|
{
|
|
|
|
Point3 testVec = patch->vecs[theVec].p - pDeltas[theVec] - theKnot;
|
|
|
|
if (testVec != zeroPoint)
|
|
|
|
{
|
|
|
|
Point3 testNorm = Normalize(testVec);
|
|
|
|
if (!(testNorm == newNorm) && !(testNorm == oldNorm))
|
|
|
|
{
|
|
|
|
// Cross product gives us the normal of the rotational axis
|
|
|
|
axis = Normalize(testNorm ^ newNorm);
|
|
|
|
// The angle is 180 degrees
|
|
|
|
angle = PI;
|
|
|
|
goto build_matrix;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Get a matrix that will transform the old point to the new one
|
|
|
|
// Cross product gives us the normal of the rotational axis
|
|
|
|
axis = Normalize(oldNorm ^ newNorm);
|
|
|
|
// Dot product gives us the angle
|
|
|
|
float dot = DotProd(oldNorm, newNorm);
|
|
|
|
if (dot >= -1.0f && dot <= 1.0f)
|
|
|
|
angle =(float) - acos(dot);
|
|
|
|
}
|
|
|
|
build_matrix:
|
|
|
|
if (angle != 0.0f)
|
|
|
|
{
|
|
|
|
// Now let's build a matrix that'll do this for us!
|
|
|
|
Quat quat = QFromAngAxis(angle, axis);
|
|
|
|
quat.MakeMatrix(theMatrix);
|
|
|
|
if (lockedHandles)
|
|
|
|
{
|
|
|
|
// If need to break the vector,
|
|
|
|
if (shiftPressed && vert.flags & PVERT_COPLANAR)
|
|
|
|
{
|
|
|
|
vert.flags &= ~PVERT_COPLANAR;
|
|
|
|
patchData->vdelta.SetVertType(primaryKnot, PVERT_COPLANAR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Process all other handles through the matrix
|
|
|
|
for (int v = 0; v < vectors; ++v)
|
|
|
|
{
|
|
|
|
int theVec = vert.vectors[v];
|
|
|
|
// Ignore the vector being moved!
|
|
|
|
if (theVec != handleIndex)
|
|
|
|
{
|
|
|
|
Point3 oldpt2 = patch->vecs[theVec].p - pDeltas[theVec];
|
|
|
|
Point3 newpt2 =(oldpt2 - theKnot) * theMatrix + theKnot;
|
|
|
|
patch->vecs[theVec].p = newpt2;
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.SetVec(theVec, newpt2 - oldpt2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Really only need to do this if neighbor knots are non-bezier
|
|
|
|
patch->computeInteriors();
|
|
|
|
|
|
|
|
patchData->UpdateChanges(patch, rpatch);
|
|
|
|
rpatch->InvalidateBindingPos ();
|
|
|
|
patchData->TempData(this)->Invalidate(PART_GEOM);
|
|
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
|
|
|
|
|
|
// Mark all objects in selection set
|
|
|
|
SetAFlag(A_HELD);
|
|
|
|
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
|
|
NotifyDependents(FOREVER, PART_GEOM, REFMSG_CHANGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::XFormVerts(
|
|
|
|
XFormProc *xproc,
|
|
|
|
TimeValue t,
|
|
|
|
Matrix3& partm,
|
|
|
|
Matrix3& tmAxis)
|
|
|
|
{
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
Matrix3 mat, imat;
|
|
|
|
Interval valid;
|
|
|
|
int numAxis;
|
|
|
|
Point3 oldpt, newpt, rel, delta;
|
|
|
|
int shiftPressed =(GetKeyState(VK_SHIFT) & 0x8000) ? 1 : 0;
|
|
|
|
static BOOL wasBroken;
|
|
|
|
static BOOL handleEdit = FALSE;
|
|
|
|
static int handleObject;
|
|
|
|
static int handleIndex;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
numAxis = ip->GetNumAxis();
|
|
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
|
|
|
|
|
|
if (!TestAFlag(A_HELD))
|
|
|
|
{
|
|
|
|
handleEdit = FALSE;
|
|
|
|
// DebugPrint("Handle edit cleared\n");
|
|
|
|
// Check all patches to see if they are altering a bezier vector handle...
|
|
|
|
if (selLevel == EP_VERTEX)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
if (!ip->SelectionFrozen() && patch->bezVecVert >= 0)
|
|
|
|
{
|
|
|
|
// Editing a bezier handle -- Go do it!
|
|
|
|
handleEdit = TRUE;
|
|
|
|
handleObject = i;
|
|
|
|
handleIndex = patch->bezVecVert;
|
|
|
|
goto edit_handles;
|
|
|
|
}
|
|
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If editing the handles, cut to the chase!
|
|
|
|
if (handleEdit)
|
|
|
|
{
|
|
|
|
edit_handles:
|
|
|
|
XFormHandles(xproc, t, partm, tmAxis, handleObject, handleIndex);
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Not doing handles, just plain ol' verts
|
|
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE); // Clear these out again
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
|
|
|
// If this is the first edit, then the delta arrays will be allocated
|
|
|
|
patchData->BeginEdit(t);
|
|
|
|
|
|
|
|
// Create a change record for this object and store a pointer to its delta info in this EditPatchData
|
|
|
|
if (!TestAFlag(A_HELD))
|
|
|
|
{
|
|
|
|
patchData->vdelta.SetSize(*patch, FALSE);
|
|
|
|
if (theHold.Holding())
|
|
|
|
{
|
|
|
|
// Hulud: here, i pass a NULL pointer because rpatch are not modified by xform
|
|
|
|
theHold.Put(new PatchRestore(patchData, this, patch, NULL, "XFormVerts"));
|
|
|
|
}
|
|
|
|
patchData->vdelta.Zero(); // Reset all deltas
|
|
|
|
patchData->ClearHandleFlag();
|
|
|
|
wasBroken = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (wasBroken)
|
|
|
|
shiftPressed = TRUE;
|
|
|
|
if (patchData->DoingHandles())
|
|
|
|
patchData->ApplyHandlesAndZero(*patch); // Reapply the slave handle deltas
|
|
|
|
else
|
|
|
|
patchData->vdelta.Zero();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compute the transforms
|
|
|
|
if (numAxis == NUMAXIS_INDIVIDUAL)
|
|
|
|
{
|
|
|
|
switch (selLevel)
|
|
|
|
{
|
|
|
|
case EP_VERTEX:
|
|
|
|
{
|
|
|
|
// Selected vertices - either directly or indirectly through selected faces or edges.
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int verts = patch->numVerts;
|
|
|
|
for (int vert = 0; vert < verts; vert++)
|
|
|
|
{
|
|
|
|
if (sel[vert])
|
|
|
|
{
|
|
|
|
tmAxis = ip->GetTransformAxis(nodes[i], vert);
|
|
|
|
mat = nodes[i]->GetObjectTM(t, &valid) * Inverse(tmAxis);
|
|
|
|
imat = Inverse(mat);
|
|
|
|
xproc->SetMat(mat);
|
|
|
|
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->verts[vert].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->verts[vert].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVert(vert, delta);
|
|
|
|
|
|
|
|
// Also affect its vectors
|
|
|
|
int vecs = patch->verts[vert].vectors.Count();
|
|
|
|
for (int vec = 0; vec < vecs; ++vec)
|
|
|
|
{
|
|
|
|
int index = patch->verts[vert].vectors[vec];
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->vecs[index].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->vecs[index].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVec(index, delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patch->computeInteriors(); // Kind of broad-spectrum -- only need to recompute affected patches
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case EP_EDGE:
|
|
|
|
case EP_PATCH:
|
|
|
|
{
|
|
|
|
// Selected vertices - either directly or indirectly through selected faces or edges.
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int verts = patch->numVerts;
|
|
|
|
for (int vert = 0; vert < verts; vert++)
|
|
|
|
{
|
|
|
|
if (sel[vert])
|
|
|
|
{
|
|
|
|
tmAxis = ip->GetTransformAxis(nodes[i], vert);
|
|
|
|
mat = nodes[i]->GetObjectTM(t, &valid) * Inverse(tmAxis);
|
|
|
|
imat = Inverse(mat);
|
|
|
|
xproc->SetMat(mat);
|
|
|
|
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->verts[vert].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->verts[vert].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVert(vert, delta);
|
|
|
|
|
|
|
|
// Also affect its vectors
|
|
|
|
int vecs = patch->verts[vert].vectors.Count();
|
|
|
|
for (int vec = 0; vec < vecs; ++vec)
|
|
|
|
{
|
|
|
|
int index = patch->verts[vert].vectors[vec];
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->vecs[index].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->vecs[index].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVec(index, delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patch->computeInteriors();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
mat = nodes[i]->GetObjectTM(t, &valid) * Inverse(tmAxis);
|
|
|
|
imat = Inverse(mat);
|
|
|
|
xproc->SetMat(mat);
|
|
|
|
|
|
|
|
// Selected vertices - either directly or indirectly through selected faces or edges.
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int verts = patch->numVerts;
|
|
|
|
for (int vert = 0; vert < verts; vert++)
|
|
|
|
{
|
|
|
|
if (sel[vert])
|
|
|
|
{
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->verts[vert].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->verts[vert].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVert(vert, delta);
|
|
|
|
|
|
|
|
// Also affect its vectors
|
|
|
|
int vecs = patch->verts[vert].vectors.Count();
|
|
|
|
for (int vec = 0; vec < vecs; ++vec)
|
|
|
|
{
|
|
|
|
int index = patch->verts[vert].vectors[vec];
|
|
|
|
// XForm the cache vertices
|
|
|
|
oldpt = patch->vecs[index].p;
|
|
|
|
newpt = xproc->proc(oldpt, mat, imat);
|
|
|
|
patch->vecs[index].p = newpt;
|
|
|
|
delta = newpt - oldpt;
|
|
|
|
|
|
|
|
// Move the delta's vertices.
|
|
|
|
patchData->vdelta.MoveVec(index, delta);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
patch->computeInteriors();
|
|
|
|
}
|
|
|
|
rpatch->InvalidateBindingPos ();
|
|
|
|
patchData->UpdateChanges(patch, NULL); // Hulud: here, i pass a NULL pointer because rpatch are not modified by xform
|
|
|
|
patchData->TempData(this)->Invalidate(PART_GEOM);
|
|
|
|
patchData->SetFlag(EPD_BEENDONE, TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Mark all objects in selection set
|
|
|
|
SetAFlag(A_HELD);
|
|
|
|
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
ClearPatchDataFlag(mcList, EPD_BEENDONE);
|
|
|
|
NotifyDependents(FOREVER, PART_GEOM, REFMSG_CHANGE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::Move(TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin)
|
|
|
|
{
|
|
|
|
MoveXForm proc(val);
|
|
|
|
XFormVerts(&proc, t, partm, tmAxis);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::Rotate(TimeValue t, Matrix3& partm, Matrix3& tmAxis, Quat& val, BOOL localOrigin)
|
|
|
|
{
|
|
|
|
RotateXForm proc(val);
|
|
|
|
XFormVerts(&proc, t, partm, tmAxis);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::Scale(TimeValue t, Matrix3& partm, Matrix3& tmAxis, Point3& val, BOOL localOrigin)
|
|
|
|
{
|
|
|
|
ScaleXForm proc(val);
|
|
|
|
XFormVerts(&proc, t, partm, tmAxis);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::TransformStart(TimeValue t)
|
|
|
|
{
|
|
|
|
if (ip)
|
|
|
|
ip->LockAxisTripods(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::TransformFinish(TimeValue t)
|
|
|
|
{
|
|
|
|
if (ip)
|
|
|
|
ip->LockAxisTripods(FALSE);
|
|
|
|
UpdateSelectDisplay();
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
patchData->UpdateChanges(patch, rpatch, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::TransformCancel(TimeValue t)
|
|
|
|
{
|
|
|
|
if (ip)
|
|
|
|
ip->LockAxisTripods(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node)
|
|
|
|
{
|
|
|
|
// Alert(_T("in ModifyObject"));
|
|
|
|
nlassert(os->obj->ClassID() == RYKOLPATCHOBJ_CLASS_ID);
|
|
|
|
// Alert(_T("ModifyObject class ID is OK"));
|
|
|
|
|
|
|
|
RPO *patchOb =(RPO*)os->obj;
|
|
|
|
EditPatchData *patchData;
|
|
|
|
|
|
|
|
if (!mc.localData)
|
|
|
|
{
|
|
|
|
mc.localData = new EditPatchData(this);
|
|
|
|
patchData =(EditPatchData*)mc.localData;
|
|
|
|
meshSteps = patchData->meshSteps = patchOb->GetMeshSteps();
|
|
|
|
// 3-18-99 to suport render steps and removal of the mental tesselator
|
|
|
|
meshStepsRender = patchData->meshStepsRender = patchOb->GetMeshStepsRender();
|
|
|
|
showInterior = patchData->showInterior = patchOb->GetShowInterior();
|
|
|
|
|
|
|
|
// meshAdaptive = patchData->meshAdaptive = patchOb->GetAdaptive(); // Future use (Not used now)
|
|
|
|
tileLevel = patchData->tileLevel = patchOb->rpatch->rTess.TileTesselLevel;
|
|
|
|
transitionType = patchData->transitionType = patchOb->rpatch->rTess.TransitionType;
|
|
|
|
tileMode = patchData->tileMode = patchOb->rpatch->rTess.ModeTile;
|
|
|
|
keepMapping = patchData->keepMapping = patchOb->rpatch->rTess.KeepMapping;
|
|
|
|
viewTess = patchData->viewTess = patchOb->GetViewTess();
|
|
|
|
prodTess = patchData->prodTess = patchOb->GetProdTess();
|
|
|
|
dispTess = patchData->dispTess = patchOb->GetDispTess();
|
|
|
|
mViewTessNormals = patchData->mViewTessNormals = patchOb->GetViewTessNormals();
|
|
|
|
mProdTessNormals = patchData->mProdTessNormals = patchOb->GetProdTessNormals();
|
|
|
|
mViewTessWeld = patchData->mViewTessWeld = patchOb->GetViewTessWeld();
|
|
|
|
mProdTessWeld = patchData->mProdTessWeld = patchOb->GetProdTessWeld();
|
|
|
|
displayLattice = patchData->displayLattice = patchOb->ShowLattice();
|
|
|
|
displaySurface = patchData->displaySurface = patchOb->showMesh;
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
patchData =(EditPatchData*)mc.localData;
|
|
|
|
}
|
|
|
|
|
|
|
|
PatchMesh &pmesh = patchOb->patch;
|
|
|
|
nlassert(pmesh.numVerts == pmesh.vertSel.GetSize());
|
|
|
|
nlassert(pmesh.getNumEdges() == pmesh.edgeSel.GetSize());
|
|
|
|
nlassert(pmesh.numPatches == pmesh.patchSel.GetSize());
|
|
|
|
|
|
|
|
patchData->Apply(t, patchOb, selLevel);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc)
|
|
|
|
{
|
|
|
|
if (mc->localData)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mc->localData;
|
|
|
|
if (patchData)
|
|
|
|
{
|
|
|
|
// The FALSE parameter indicates the the mesh cache itself is
|
|
|
|
// invalid in addition to any other caches that depend on the
|
|
|
|
// mesh cache.
|
|
|
|
patchData->Invalidate(partID, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetDisplaySurface(BOOL sw)
|
|
|
|
{
|
|
|
|
sw = TRUE;
|
|
|
|
displaySurface = sw;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
patchData->displaySurface = sw;
|
|
|
|
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetDisplayLattice(BOOL sw)
|
|
|
|
{
|
|
|
|
displayLattice = sw;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
patchData->displayLattice = sw;
|
|
|
|
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
if (sw)
|
|
|
|
patch->SetDispFlag(DISP_LATTICE);
|
|
|
|
else
|
|
|
|
patch->ClearDispFlag(DISP_LATTICE);
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetPropagate(BOOL sw)
|
|
|
|
{
|
|
|
|
propagate = sw;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetMeshSteps(int steps)
|
|
|
|
{
|
|
|
|
meshSteps = steps;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
patch->SetMeshSteps(steps);
|
|
|
|
patchData->meshSteps = steps;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetTileMode (bool bTile)
|
|
|
|
{
|
|
|
|
tileMode=bTile;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rpatch->rTess.ModeTile=bTile;
|
|
|
|
patchData->tileMode=bTile;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetKeepMapping (bool bKeep)
|
|
|
|
{
|
|
|
|
keepMapping=bKeep;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rpatch->rTess.KeepMapping=bKeep;
|
|
|
|
patchData->keepMapping=bKeep;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetTileSteps(int steps)
|
|
|
|
{
|
|
|
|
tileLevel=steps;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rpatch->rTess.TileTesselLevel=steps;
|
|
|
|
patchData->tileLevel=steps;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetTransitionLevel(int transition)
|
|
|
|
{
|
|
|
|
transitionType=transition;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
rpatch->rTess.TransitionType=transition;
|
|
|
|
patchData->transitionType=transition;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// 3-18-99 to suport render steps and removal of the mental tesselator
|
|
|
|
void EditPatchMod::SetMeshStepsRender(int steps)
|
|
|
|
{
|
|
|
|
meshStepsRender = steps;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
patch->SetMeshStepsRender(steps);
|
|
|
|
patchData->meshStepsRender = steps;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::SetShowInterior(BOOL si)
|
|
|
|
{
|
|
|
|
showInterior = si;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
if (!patch)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
patch->SetShowInterior(si);
|
|
|
|
patchData->showInterior = si;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
// Future use (Not used now)
|
|
|
|
void EditPatchMod::SetMeshAdaptive(BOOL sw)
|
|
|
|
{
|
|
|
|
meshAdaptive = sw;
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime());
|
|
|
|
patch->SetAdaptive(sw);
|
|
|
|
patchData->meshAdaptive = sw;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->TempData(this)->Invalidate(PART_DISPLAY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NotifyDependents(FOREVER, PART_DISPLAY, REFMSG_CHANGE);
|
|
|
|
ip->RedrawViews(ip->GetTime(), REDRAW_NORMAL);
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
int EditPatchMod::SubObjectIndex(HitRecord *hitRec)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)hitRec->modContext->localData;
|
|
|
|
if (!patchData)
|
|
|
|
return 0;
|
|
|
|
if (!ip)
|
|
|
|
return 0;
|
|
|
|
TimeValue t = ip->GetTime();
|
|
|
|
PatchHitData *hit =(PatchHitData *)(hitRec->hitData);
|
|
|
|
switch (selLevel)
|
|
|
|
{
|
|
|
|
case EP_VERTEX:
|
|
|
|
{
|
|
|
|
if (hit->type != PATCH_HIT_VERTEX)
|
|
|
|
return 0;
|
|
|
|
int hitIndex = hit->index;
|
|
|
|
return hitIndex;
|
|
|
|
}
|
|
|
|
case EP_EDGE:
|
|
|
|
{
|
|
|
|
int hitIndex = hit->index;
|
|
|
|
return hitIndex;
|
|
|
|
}
|
|
|
|
case EP_PATCH:
|
|
|
|
{
|
|
|
|
int hitIndex = hit->index;
|
|
|
|
return hitIndex;
|
|
|
|
}
|
|
|
|
case EP_TILE:
|
|
|
|
{
|
|
|
|
int hitIndex = hit->index;
|
|
|
|
return hitIndex;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::GetSubObjectTMs(
|
|
|
|
SubObjAxisCallback *cb, TimeValue t, INode *node, ModContext *mc)
|
|
|
|
{
|
|
|
|
Interval valid;
|
|
|
|
if (mc->localData)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mc->localData;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(t, rpatch);
|
|
|
|
// Watch out -- The system can call us even if we didn't get a valid patch object
|
|
|
|
if (!patch)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (selLevel)
|
|
|
|
{
|
|
|
|
case EP_VERTEX:
|
|
|
|
{
|
|
|
|
Matrix3 otm = node->GetObjectTM(t, &valid);
|
|
|
|
Matrix3 tm = node->GetNodeTM(t, &valid);
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int count = sel.GetSize();
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
{
|
|
|
|
if (sel[i])
|
|
|
|
{
|
|
|
|
tm.SetTrans(patch->verts[i].p * otm);
|
|
|
|
cb->TM(tm, i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EP_EDGE:
|
|
|
|
case EP_PATCH:
|
|
|
|
{
|
|
|
|
Matrix3 otm = node->GetObjectTM(t, &valid);
|
|
|
|
Matrix3 tm = node->GetNodeTM(t, &valid);
|
|
|
|
Box3 box;
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int count = sel.GetSize();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
{
|
|
|
|
if (sel[i])
|
|
|
|
box += patch->verts[i].p;
|
|
|
|
}
|
|
|
|
tm.SetTrans(otm * box.Center());
|
|
|
|
cb->TM(tm, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EP_TILE:
|
|
|
|
{
|
|
|
|
bool bHasSel;
|
|
|
|
Matrix3 pt=rpatch->GetSelTileTm(*patch, t, node, bHasSel);
|
|
|
|
if (bHasSel)
|
|
|
|
cb->TM(pt, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::GetSubObjectCenters(
|
|
|
|
SubObjAxisCallback *cb, TimeValue t, INode *node, ModContext *mc)
|
|
|
|
{
|
|
|
|
Interval valid;
|
|
|
|
Matrix3 tm = node->GetObjectTM(t, &valid);
|
|
|
|
|
|
|
|
nlassert(ip);
|
|
|
|
if (mc->localData)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mc->localData;
|
|
|
|
RPatchMesh *rpatch;
|
|
|
|
PatchMesh *patch = patchData->TempData(this)->GetPatch(ip->GetTime(), rpatch);
|
|
|
|
|
|
|
|
rpatch->UpdateBinding (*patch, t);
|
|
|
|
|
|
|
|
// Watch out -- The system can call us even if we didn't get a valid patch object
|
|
|
|
if (!patch)
|
|
|
|
return;
|
|
|
|
|
|
|
|
switch (selLevel)
|
|
|
|
{
|
|
|
|
case EP_VERTEX:
|
|
|
|
{
|
|
|
|
Box3 box;
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int verts = patch->numVerts;
|
|
|
|
for (int i = 0; i < verts; i++)
|
|
|
|
{
|
|
|
|
if (sel[i])
|
|
|
|
cb->Center(patch->verts[i].p * tm, i);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EP_EDGE:
|
|
|
|
case EP_PATCH:
|
|
|
|
{
|
|
|
|
Box3 box;
|
|
|
|
BOOL bHasSel = FALSE;
|
|
|
|
BitArray sel = patch->VertexTempSel();
|
|
|
|
int verts = patch->numVerts;
|
|
|
|
for (int i = 0; i < verts; i++)
|
|
|
|
{
|
|
|
|
if (sel[i])
|
|
|
|
{
|
|
|
|
box += patch->verts[i].p * tm;
|
|
|
|
bHasSel = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bHasSel)
|
|
|
|
cb->Center(box.Center(), 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case EP_TILE:
|
|
|
|
{
|
|
|
|
bool bHasSel;
|
|
|
|
Point3 pt=rpatch->GetSelTileCenter(*patch, t, node, bHasSel);
|
|
|
|
if (bHasSel)
|
|
|
|
cb->Center(pt, 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
cb->Center(tm.GetTrans(), 0);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
BOOL EditPatchMod::DependOnTopology(ModContext &mc)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mc.localData;
|
|
|
|
if (patchData)
|
|
|
|
{
|
|
|
|
if (patchData->GetFlag(EPD_HASDATA))
|
|
|
|
{
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void EditPatchMod::DeletePatchDataTempData()
|
|
|
|
{
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
if (patchData->tempData)
|
|
|
|
{
|
|
|
|
delete patchData->tempData;
|
|
|
|
}
|
|
|
|
patchData->tempData = NULL;
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void EditPatchMod::CreatePatchDataTempData()
|
|
|
|
{
|
|
|
|
ModContextList mcList;
|
|
|
|
INodeTab nodes;
|
|
|
|
|
|
|
|
if (!ip)
|
|
|
|
return;
|
|
|
|
ip->GetModContexts(mcList, nodes);
|
|
|
|
|
|
|
|
for (int i = 0; i < mcList.Count(); i++)
|
|
|
|
{
|
|
|
|
EditPatchData *patchData =(EditPatchData*)mcList[i]->localData;
|
|
|
|
if (!patchData)
|
|
|
|
continue;
|
|
|
|
if (!patchData->tempData)
|
|
|
|
{
|
|
|
|
patchData->tempData = new EPTempData(this, patchData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nodes.DisposeTemporary();
|
|
|
|
}
|
|
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
|
|
|
|
|
|
void EditPatchMod::SetRememberedVertType(int type)
|
|
|
|
{
|
|
|
|
if (rememberedPatch)
|
|
|
|
ChangeRememberedVert(type);
|
|
|
|
else
|
|
|
|
ChangeSelVerts(type);
|
|
|
|
}
|
|
|
|
|