khanat-opennel-code/code/nel/tools/3d/plugin_max/nel_vertex_tree_paint/vertex_tree_paint.cpp
2016-11-20 17:15:56 +01:00

1353 lines
30 KiB
C++

/**********************************************************************
*<
FILE: vertex_tree_paint.cpp
DESCRIPTION: Modifier implementation
CREATED BY: Christer Janson, Nikolai Sander
HISTORY:
*> Copyright (c) 1997, All Rights Reserved.
**********************************************************************/
#include "vertex_tree_paint.h"
#include "meshdelta.h"
// flags:
#define VP_DISP_END_RESULT 0x01
static WNDPROC colorSwatchOriginalWndProc;
static HIMAGELIST hButtonImages = NULL;
static void LoadImages()
{
if (hButtonImages) return;
HBITMAP hBitmap, hMask;
hButtonImages = ImageList_Create(15, 14, ILC_MASK, 2, 0); // 17 is kluge to center square. -SA
hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BUTTONS));
hMask = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_BUTTON_MASK));
ImageList_Add(hButtonImages, hBitmap, hMask);
DeleteObject(hBitmap);
DeleteObject(hMask);
}
ClassDesc* GetVertexPaintDesc();
class VertexPaintClassDesc :public ClassDesc
{
public:
int IsPublic() { return 1; }
void * Create(BOOL loading = FALSE) { return new VertexPaint(); }
const TCHAR * ClassName() { return GetString(IDS_CLASS_NAME); }
SClass_ID SuperClassID() { return OSM_CLASS_ID; }
Class_ID ClassID() { return VERTEX_TREE_PAINT_CLASS_ID; }
const TCHAR* Category() { return GetString(IDS_CATEGORY); }
void ResetClassParams(BOOL fileReset) {}
};
static VertexPaintClassDesc VertexPaintDesc;
ClassDesc* GetVertexPaintDesc() { return &VertexPaintDesc; }
static INT_PTR CALLBACK VertexPaintDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
int numPoints;
VertexPaint *mod = (VertexPaint*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
if (!mod && msg != WM_INITDIALOG) return FALSE;
int comboResult;
// Manages Spinners.
if (((msg == CC_SPINNER_BUTTONUP) && HIWORD(wParam)) ||
((msg == CC_SPINNER_CHANGE)))
{
ISpinnerControl *spin;
spin = (ISpinnerControl *)lParam;
switch (LOWORD(wParam))
{
case IDC_TINT_SPIN:
if ((msg == CC_SPINNER_CHANGE))
{
mod->fTint = spin->GetFVal() / 100;
}
break;
case IDC_BEND_SPIN:
if ((msg == CC_SPINNER_CHANGE))
{
mod->fGradientBend = spin->GetFVal() / 100;
}
break;
}
}
switch (msg)
{
case WM_INITDIALOG:
LoadImages();
mod = (VertexPaint*)lParam;
SetWindowLongPtr(hWnd, GWLP_USERDATA, lParam);
mod->hParams = hWnd;
mod->iPaintButton = GetICustButton(GetDlgItem(hWnd, IDC_PAINT));
mod->iPaintButton->SetType(CBT_CHECK);
mod->iPaintButton->SetHighlightColor(GREEN_WASH);
mod->iPaintButton->SetCheck(mod->ip->GetCommandMode()->ID() == CID_PAINT &&
!((PaintMouseProc *)mod->ip->GetCommandMode()->MouseProc(&numPoints))->GetPickMode());
mod->iPaintButton->SetImage(hButtonImages, 0, 0, 0, 0, 15, 14);
mod->iPaintButton->SetTooltip(TRUE, GetString(IDS_PAINT));
mod->iPickButton = GetICustButton(GetDlgItem(hWnd, IDC_PICK));
mod->iPickButton->SetType(CBT_CHECK);
mod->iPickButton->SetHighlightColor(GREEN_WASH);
mod->iPickButton->SetCheck(mod->ip->GetCommandMode()->ID() == CID_PAINT &&
((PaintMouseProc *)mod->ip->GetCommandMode()->MouseProc(&numPoints))->GetPickMode());
mod->iPickButton->SetImage(hButtonImages, 1, 1, 1, 1, 15, 14);
mod->iPickButton->SetTooltip(TRUE, GetString(IDS_PICK));
mod->iColor = GetIColorSwatch(GetDlgItem(hWnd, IDC_COLOR));
// change current Color according to editMode
mod->reloadBkupColor();
// Get interface For ZGradient, reload bkuped colors
mod->iColorGradient[0] = GetIColorSwatch(GetDlgItem(hWnd, IDC_PALETTE_GRAD0));
mod->iColorGradient[1] = GetIColorSwatch(GetDlgItem(hWnd, IDC_PALETTE_GRAD1));
mod->iColorGradient[0]->SetColor(mod->lastGradientColor[0]);
mod->iColorGradient[1]->SetColor(mod->lastGradientColor[1]);
// Init comboBox
SendDlgItemMessage(hWnd, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)"Tree Weight");
SendDlgItemMessage(hWnd, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)"Phase Level 1");
SendDlgItemMessage(hWnd, IDC_COMBO_TYPE, CB_ADDSTRING, 0, (LPARAM)"Phase Level 2");
SendDlgItemMessage(hWnd, IDC_COMBO_TYPE, CB_SETCURSEL, mod->getEditionType(), 0);
// If paint mode at last edit.
if (mod->_LastPaintMode)
{
// ActivatePaint / check button.
mod->ActivatePaint(TRUE);
mod->iPaintButton->SetCheck(TRUE);
}
break;
case WM_POSTINIT:
mod->InitPalettes();
break;
case CC_COLOR_CHANGE:
if (LOWORD(wParam) == IDC_COLOR)
{
IColorSwatch* iCol = (IColorSwatch*)lParam;
switch (mod->getEditionType())
{
case 0: mod->lastWeightColor = iCol->GetColor(); break;
case 1:
case 2:
mod->lastPhaseColor = iCol->GetColor(); break;
}
}
break;
case WM_DESTROY:
mod->SavePalettes();
mod->iPaintButton = NULL;
mod->iPickButton = NULL;
mod->iColor = NULL;
mod->iColorGradient[0] = NULL;
mod->iColorGradient[1] = NULL;
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_PAINT:
mod->ActivatePaint(mod->iPaintButton->IsChecked());
break;
case IDC_PICK:
mod->ActivatePaint(mod->iPickButton->IsChecked(), TRUE);
break;
case IDC_VC_ON:
mod->TurnVCOn(FALSE);
break;
case IDC_SHADED:
mod->TurnVCOn(TRUE);
break;
case IDC_COMBO_TYPE:
// Init default type.
comboResult = SendDlgItemMessage(hWnd, IDC_COMBO_TYPE, CB_GETCURSEL, 0, 0);
mod->setEditionType(comboResult);
break;
case IDC_BUTTON_FILL:
mod->fillSelectionColor();
break;
case IDC_BUTTON_GRADIENT:
mod->fillSelectionGradientColor();
break;
case IDC_BUTTON_GRAD0:
mod->iColorGradient[0]->SetColor(RGB(0, 0, 0));
mod->iColorGradient[1]->SetColor(RGB(85, 85, 85));
break;
case IDC_BUTTON_GRAD1:
mod->iColorGradient[0]->SetColor(RGB(85, 85, 85));
mod->iColorGradient[1]->SetColor(RGB(170, 170, 170));
break;
case IDC_BUTTON_GRAD2:
mod->iColorGradient[0]->SetColor(RGB(170, 170, 170));
mod->iColorGradient[1]->SetColor(RGB(255, 255, 255));
break;
}
break;
default:
return FALSE;
}
return TRUE;
}
// Subclass procedure
LRESULT APIENTRY colorSwatchSubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_LBUTTONDBLCLK:
{
HWND hPanel = GetParent(hwnd);
LONG_PTR mod = GetWindowLongPtr(hPanel, GWLP_USERDATA);
if (mod)
{
((VertexPaint*)mod)->PaletteButton(hwnd);
}
}
break;
case WM_DESTROY:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)colorSwatchOriginalWndProc);
// Fallthrough...
default:
return CallWindowProc(colorSwatchOriginalWndProc, hwnd, uMsg, wParam, lParam);
break;
}
return 0;
}
IObjParam *VertexPaint::ip = NULL;
HWND VertexPaint::hParams = NULL;
VertexPaint* VertexPaint::editMod = NULL;
ICustButton* VertexPaint::iPaintButton = NULL;
ICustButton* VertexPaint::iPickButton = NULL;
IColorSwatch* VertexPaint::iColor = NULL;
COLORREF VertexPaint::lastWeightColor = RGB(85, 85, 85);
COLORREF VertexPaint::lastPhaseColor = RGB(0, 0, 0);
COLORREF VertexPaint::palColors[] =
{
//RGB(32, 32, 32), RGB( 96,96,96), RGB( 160,160,160), RGB(224,224,224) };
RGB(0, 0, 0), RGB(85,85,85), RGB(170,170,170), RGB(255,255,255),
RGB(42, 42, 42), RGB(127, 127, 127), RGB(212, 212, 212) };
IColorSwatch* VertexPaint::iColorGradient[] = { NULL, NULL };
COLORREF VertexPaint::lastGradientColor[] = { RGB(0, 0, 0), RGB(85, 85, 85) };
//--- VertexPaint -------------------------------------------------------
VertexPaint::VertexPaint() : iTint(NULL), fTint(1.0f), iGradientBend(NULL), fGradientBend(0.0f)
{
flags = 0x0;
_EditType = 0;
_LastPaintMode = false;
}
VertexPaint::~VertexPaint()
{
}
Interval VertexPaint::LocalValidity(TimeValue t)
{
return FOREVER;
}
BOOL VertexPaint::DependOnTopology(ModContext &mc)
{
return TRUE;
}
RefTargetHandle VertexPaint::Clone(RemapDir& remap)
{
VertexPaint* newmod = new VertexPaint();
return(newmod);
}
void VertexPaint::NotifyInputChanged(Interval changeInt, PartID partID, RefMessage message, ModContext *mc)
{
if (!mc->localData) return;
((VertexPaintData*)mc->localData)->FreeCache();
}
void VertexPaint::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *node)
{
if (!os->obj->IsSubClassOf(triObjectClassID)) return;
os->obj->ReadyChannelsForMod(GEOM_CHANNEL | TOPO_CHANNEL | VERTCOLOR_CHANNEL | TEXMAP_CHANNEL);
TriObject *tobj = (TriObject*)os->obj;
VertexPaintData *d = (VertexPaintData*)mc.localData;
Mesh* mesh = &tobj->GetMesh();
if (mesh)
{
// We don't have any VColors yet, so we allocate the vcfaces
// and set all vcolors to black (index 0)
if (!mesh->vcFace)
{
mesh->setNumVCFaces(mesh->getNumFaces());
mesh->setNumVertCol(1);
mesh->vertCol[0] = Color(0, 0, 0);
for (int f = 0; f < mesh->getNumFaces(); f++)
{
mesh->vcFace[f].t[0] = 0;
mesh->vcFace[f].t[1] = 0;
mesh->vcFace[f].t[2] = 0;
}
}
if (!d) mc.localData = d = new VertexPaintData(tobj->GetMesh());
if (!d->GetMesh()) d->SetCache(*mesh);
{
MeshDelta md(*mesh);
//MeshDelta mdc;
//if(cache) mdc.InitToMesh(*cache);
// If the incoming Mesh had no vertex colors, this will add a default map to start with.
// The default map has the same topology as the Mesh (so one color per vertex),
// with all colors set to white.
if (!mesh->mapSupport(0)) md.AddVertexColors();
//if (cache && !cache->mapSupport(0)) mdc.AddVertexColors ();
// We used two routines -- VCreate to add new map vertices, and FRemap to make the
// existing map faces use the new verts. frFlags tell FRemap which vertices on a face
// should be "remapped", and the ww array contains the new locations.
VertColor nvc;
int j;
for (int v = 0; v < d->GetNumColors(); v++)
{
ColorData cd = d->GetColorData(v);
// Edition Mode ??
if (editMod == this)
{
nvc = Color(cd.color);
// change color to view only monochromatic info for this channel;
switch (_EditType)
{
case 0: nvc.y = nvc.z = nvc.x;
nvc.y *= 0.7f;
nvc.z *= 0.7f;
break;
case 1: nvc.x = nvc.z = nvc.y;
nvc.x *= 0.7f;
nvc.z *= 0.7f;
break;
case 2: nvc.x = nvc.y = nvc.z;
nvc.x *= 0.7f;
nvc.y *= 0.7f;
break;
}
}
else
{
// replace the VertexColor of the outgoing mesh
nvc = Color(cd.color);
}
DWORD ww[3], frFlags;
md.map->VCreate(&nvc);
// increase the number of vcol's and set the vcfaces as well
for (int i = 0; i < d->GetNVert(v).faces.Count(); i++)
{
j = d->GetNVert(v).whichVertex[i];
frFlags = (1 << j);
ww[j] = md.map->outVNum() - 1;
md.map->FRemap(d->GetNVert(v).faces[i], frFlags, ww);
}
}
md.Apply(*mesh);
}
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
os->obj->UpdateValidity(VERT_COLOR_CHAN_NUM, Interval(t, t));
}
}
static bool oldShowEnd;
void VertexPaint::BeginEditParams(IObjParam *ip, ULONG flags, Animatable *prev)
{
this->ip = ip;
editMod = this;
if (!hParams)
{
hParams = ip->AddRollupPage(hInstance, MAKEINTRESOURCE(IDD_PANEL), VertexPaintDlgProc, GetString(IDS_PARAMS), (LPARAM)this);
// Subclass the palette controls
hPaletteWnd[0] = GetDlgItem(hParams, IDC_PALETTE_1);
hPaletteWnd[1] = GetDlgItem(hParams, IDC_PALETTE_2);
hPaletteWnd[2] = GetDlgItem(hParams, IDC_PALETTE_3);
hPaletteWnd[3] = GetDlgItem(hParams, IDC_PALETTE_4);
hPaletteWnd[4] = GetDlgItem(hParams, IDC_PALETTE_5);
hPaletteWnd[5] = GetDlgItem(hParams, IDC_PALETTE_6);
hPaletteWnd[6] = GetDlgItem(hParams, IDC_PALETTE_7);
int i;
for (i = 0; i < NUMPALETTES; i++)
{
colorSwatchOriginalWndProc = (WNDPROC)SetWindowLongPtr(hPaletteWnd[i], GWLP_WNDPROC, (LONG_PTR)colorSwatchSubclassWndProc);
}
SendMessage(hParams, WM_POSTINIT, 0, 0);
}
else
{
SetWindowLongPtr(hParams, GWLP_USERDATA, (LONG_PTR)this);
}
iTint = SetupIntSpinner(hParams, IDC_TINT_SPIN, IDC_TINT, 0, 100, (int)(fTint*100.0f));
// Init Gradient Bend spinner
iGradientBend = SetupIntSpinner(hParams, IDC_BEND_SPIN, IDC_BEND, 0, 100, (int)(fGradientBend*100.0f));
// Set show end result.
oldShowEnd = ip->GetShowEndResult() ? TRUE : FALSE;
ip->SetShowEndResult(GetFlag(VP_DISP_END_RESULT));
// Force an eval to update caches.
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
}
void VertexPaint::EndEditParams(IObjParam *ip, ULONG flags, Animatable *next)
{
// Dsiable Painting.
bool lpm = _LastPaintMode;
ActivatePaint(FALSE);
// bkup lastPainMode
_LastPaintMode = lpm;
ReleaseISpinner(iTint);
ReleaseISpinner(iGradientBend);
ModContextList list;
INodeTab nodes;
ip->GetModContexts(list, nodes);
for (int i = 0; i < list.Count(); i++)
{
VertexPaintData *vd = (VertexPaintData*)list[i]->localData;
if (vd) vd->FreeCache();
}
nodes.DisposeTemporary();
// Reset show end result
SetFlag(VP_DISP_END_RESULT, ip->GetShowEndResult() ? TRUE : FALSE);
ip->SetShowEndResult(oldShowEnd);
// Exit editMod => draw true colored weights.
editMod = NULL;
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
ip->DeleteRollupPage(hParams);
hParams = NULL;
iTint = NULL;
iGradientBend = NULL;
this->ip = NULL;
}
//From ReferenceMaker
RefResult VertexPaint::NotifyRefChanged(const Interval& changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message, BOOL propagate)
{
return REF_SUCCEED;
}
int VertexPaint::NumRefs()
{
return 0;
}
RefTargetHandle VertexPaint::GetReference(int i)
{
return NULL;
}
void VertexPaint::SetReference(int i, RefTargetHandle rtarg)
{
}
int VertexPaint::NumSubs()
{
return 0;
}
Animatable* VertexPaint::SubAnim(int i)
{
return NULL;
}
TSTR VertexPaint::SubAnimName(int i)
{
return _T("");
}
#define VERSION_CHUNKID 0x100
#define COLORLIST_CHUNKID 0x120
static int currentVersion = 1;
IOResult VertexPaint::Load(ILoad *iload)
{
IOResult res;
ULONG nb;
int version = 1;
Modifier::Load(iload);
while (IO_OK == (res = iload->OpenChunk()))
{
switch (iload->CurChunkID())
{
case VERSION_CHUNKID:
iload->Read(&version, sizeof(version), &nb);
break;
}
iload->CloseChunk();
if (res != IO_OK) return res;
}
return IO_OK;
}
IOResult VertexPaint::Save(ISave *isave)
{
IOResult res;
ULONG nb;
Modifier::Save(isave);
isave->BeginChunk(VERSION_CHUNKID);
res = isave->Write(&currentVersion, sizeof(int), &nb);
isave->EndChunk();
return IO_OK;
}
IOResult VertexPaint::SaveLocalData(ISave *isave, LocalModData *ld)
{
VertexPaintData* d = (VertexPaintData*)ld;
IOResult res;
ULONG nb;
int numColors;
ColorData col;
isave->BeginChunk(VERSION_CHUNKID);
res = isave->Write(&currentVersion, sizeof(int), &nb);
isave->EndChunk();
isave->BeginChunk(COLORLIST_CHUNKID);
numColors = d->GetNumColors();
res = isave->Write(&numColors, sizeof(int), &nb);
for (int i = 0; i < numColors; i++)
{
col = d->GetColorData(i);
isave->Write(&col.color, sizeof(col.color), &nb);
}
isave->EndChunk();
return IO_OK;
}
IOResult VertexPaint::LoadLocalData(ILoad *iload, LocalModData **pld)
{
VertexPaintData *d = new VertexPaintData;
IOResult res;
ULONG nb;
int version = 1;
int numColors;
ColorData col;
*pld = d;
while (IO_OK == (res = iload->OpenChunk()))
{
switch (iload->CurChunkID())
{
case VERSION_CHUNKID:
iload->Read(&version, sizeof(version), &nb);
break;
case COLORLIST_CHUNKID:
{
iload->Read(&numColors, sizeof(int), &nb);
d->AllocColorData(numColors);
for (int i = 0; i < numColors; i++)
{
iload->Read(&col.color, sizeof(col.color), &nb);
d->SetColor(i, col);
}
}
break;
}
iload->CloseChunk();
if (res != IO_OK) return res;
}
return IO_OK;
}
void VertexPaint::PaletteButton(HWND hWnd)
{
IColorSwatch* iPal = GetIColorSwatch(hWnd);
if (iPal && iColor)
{
iColor->SetColor(iPal->GetColor(), TRUE);
}
}
void VertexPaint::InitPalettes()
{
IColorSwatch* c;
for (int i = 0; i < NUMPALETTES; i++)
{
c = GetIColorSwatch(hPaletteWnd[i]);
c->SetColor(palColors[i]);
ReleaseIColorSwatch(c);
}
}
void VertexPaint::SavePalettes()
{
IColorSwatch* c;
for (int i = 0; i < NUMPALETTES; i++)
{
c = GetIColorSwatch(hPaletteWnd[i]);
palColors[i] = c->GetColor();
ReleaseIColorSwatch(c);
}
// Save Gradient Palettes.
lastGradientColor[0] = iColorGradient[0]->GetColor();
lastGradientColor[1] = iColorGradient[1]->GetColor();
}
void VertexPaint::TurnVCOn(BOOL shaded)
{
ModContextList list;
INodeTab NodeTab;
// Only the selected nodes will be affected
ip->GetModContexts(list, NodeTab);
for (int i = 0; i < NodeTab.Count(); i++)
{
if (shaded)
NodeTab[i]->SetShadeCVerts(!NodeTab[i]->GetShadeCVerts());
else
NodeTab[i]->SetCVertMode(!NodeTab[i]->GetCVertMode());
}
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
ip->RedrawViews(ip->GetTime());
}
// *****************************************************************
void VertexPaint::setEditionType(int editMode)
{
if (editMode < 0) editMode = 0;
if (editMode > 2) editMode = 2;
// backup current Color according to editMode
backupCurrentColor();
_EditType = editMode;
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
ip->RedrawViews(ip->GetTime());
// Change Color Swatch according to editMode.
IColorSwatch* c;
for (int i = 0; i < NUMPALETTES; i++)
{
// Change palColors[i].
int val;
if (editMode == 0)
val = i * 255 / (4 - 1); // 0, 85, 170, 255
else
val = (i * 256 + 128) / 4; // 32, 96, 160, 224
// Change Addditional Palette colors.
if (i >= 4)
{
if (editMode == 0)
val = 42 + (i - 4) * 255 / (4 - 1); // 42, 127, 212
else
val = 0; // Phase not used
}
// Setup Color
palColors[i] = RGB(val, val, val);
c = GetIColorSwatch(hPaletteWnd[i]);
c->SetColor(palColors[i]);
ReleaseIColorSwatch(c);
}
// change current Color according to editMode
reloadBkupColor();
}
// *****************************************************************
void VertexPaint::backupCurrentColor()
{
switch (getEditionType())
{
case 0: lastWeightColor = iColor->GetColor(); break;
case 1:
case 2: lastPhaseColor = iColor->GetColor(); break;
}
}
void VertexPaint::reloadBkupColor()
{
// Change current color according to editMode.
switch (getEditionType())
{
case 0: iColor->SetColor(lastWeightColor); break;
case 1:
case 2: iColor->SetColor(lastPhaseColor); break;
}
}
// *****************************************************************
void VertexPaint::fillSelectionColor()
{
int mci;
// Put Data in Undo/Redo List.
if (!theHold.Holding())
theHold.Begin();
ModContextList modContexts;
INodeTab nodeTab;
GetCOREInterface()->GetModContexts(modContexts, nodeTab);
for (mci = 0; mci < modContexts.Count(); mci++)
{
ModContext *mc = modContexts[mci];
if (mc && mc->localData)
theHold.Put(new VertexPaintRestore((VertexPaintData*)mc->localData, this));
}
theHold.Accept(GetString(IDS_RESTORE_FILL));
// Which Component to change??
VertexPaintData::TComponent whichComponent;
switch (getEditionType())
{
case 0: whichComponent = VertexPaintData::Red; break;
case 1: whichComponent = VertexPaintData::Green; break;
case 2: whichComponent = VertexPaintData::Blue; break;
}
// Modify all meshes.
for (mci = 0; mci < modContexts.Count(); mci++)
{
ModContext *mc = modContexts[mci];
if (mc && mc->localData)
{
VertexPaintData* d = (VertexPaintData*)mc->localData;
Mesh* mesh = d->GetMesh();
if (mesh && mesh->vertCol)
{
// For all faces of the mesh
for (int fi = 0; fi < mesh->getNumFaces(); fi++)
{
Face* f = &mesh->faces[fi];
for (int i = 0; i < 3; i++)
{
// Skip painting because not selected??
if (mesh->selLevel == MESH_VERTEX && !mesh->VertSel()[f->v[i]])
continue;
if (mesh->selLevel == MESH_FACE && !mesh->FaceSel()[fi])
continue;
// Also skip if face is hidden.
if (f->Hidden())
continue;
// Apply painting
d->SetColor(f->v[i], 1, GetActiveColor(), whichComponent);
}
}
}
}
}
// refresh
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
ip->RedrawViews(ip->GetTime());
}
// *****************************************************************
void VertexPaint::fillSelectionGradientColor()
{
int mci;
// Put Data in Undo/Redo List.
if (!theHold.Holding())
theHold.Begin();
ModContextList modContexts;
INodeTab nodeTab;
GetCOREInterface()->GetModContexts(modContexts, nodeTab);
for (mci = 0; mci < modContexts.Count(); mci++)
{
ModContext *mc = modContexts[mci];
if (mc && mc->localData)
theHold.Put(new VertexPaintRestore((VertexPaintData*)mc->localData, this));
}
theHold.Accept(GetString(IDS_RESTORE_GRADIENT));
// Which Component to change??
VertexPaintData::TComponent whichComponent;
switch (getEditionType())
{
case 0: whichComponent = VertexPaintData::Red; break;
case 1: whichComponent = VertexPaintData::Green; break;
case 2: whichComponent = VertexPaintData::Blue; break;
}
COLORREF grad0 = iColorGradient[0]->GetColor();
COLORREF grad1 = iColorGradient[1]->GetColor();
// Get Matrix to viewport.
Matrix3 viewMat;
{
ViewExp *ve = GetCOREInterface()->GetActiveViewport();
// The affine TM transforms from world coords to view coords
ve->GetAffineTM(viewMat);
GetCOREInterface()->ReleaseViewport(ve);
}
// Modify all meshes.
for (mci = 0; mci < modContexts.Count(); mci++)
{
ModContext *mc = modContexts[mci];
if (mc && mc->localData)
{
VertexPaintData* d = (VertexPaintData*)mc->localData;
Mesh* mesh = d->GetMesh();
if (mesh && mesh->vertCol)
{
float yMini = FLT_MAX;
float yMaxi = -FLT_MAX;
// 1st, For all faces of the mesh, comute BBox of selection.
int fi;
for (fi = 0; fi < mesh->getNumFaces(); fi++)
{
Face* f = &mesh->faces[fi];
for (int i = 0; i < 3; i++)
{
// Skip painting because not selected??
if (mesh->selLevel == MESH_VERTEX && !mesh->VertSel()[f->v[i]])
continue;
if (mesh->selLevel == MESH_FACE && !mesh->FaceSel()[fi])
continue;
// Also skip if face is hidden.
if (f->Hidden())
continue;
// Transform to viewSpace.
Point3 p = viewMat*mesh->getVert(f->v[i]);
// extend bbox.
yMini = p.y < yMini ? p.y : yMini;
yMaxi = p.y > yMaxi ? p.y : yMaxi;
}
}
// 2nd, For all faces of the mesh, fill with gradient
for (fi = 0; fi < mesh->getNumFaces(); fi++)
{
Face* f = &mesh->faces[fi];
for (int i = 0; i < 3; i++)
{
// Skip painting because not selected??
if (mesh->selLevel == MESH_VERTEX && !mesh->VertSel()[f->v[i]])
continue;
if (mesh->selLevel == MESH_FACE && !mesh->FaceSel()[fi])
continue;
// Also skip if face is hidden.
if (f->Hidden())
continue;
// Compute gradientValue.
float gradValue;
Point3 p = viewMat*mesh->getVert(f->v[i]);
gradValue = (p.y - yMini) / (yMaxi - yMini);
// Modifie with bendPower. 1->6.
float pow = 1 + fGradientBend * 5;
gradValue = powf(gradValue, pow);
// Apply painting
// Reset To 0.
d->SetColor(f->v[i], 1, grad0, whichComponent);
// Blend with gradientValue.
d->SetColor(f->v[i], gradValue, grad1, whichComponent);
}
}
}
}
}
// refresh
NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
ip->RedrawViews(ip->GetTime());
}
// *****************************************************************
VertexPaintData::VertexPaintData(Mesh& m) : mesh(NULL), colordata(NULL), nverts(NULL),
nvcverts(NULL), numColors(0), numnverts(0), numnvcverts(0)
{
SetCache(m);
}
VertexPaintData::VertexPaintData() : mesh(NULL), colordata(NULL), nverts(NULL),
nvcverts(NULL), numColors(0), numnverts(0), numnvcverts(0)
{
}
VertexPaintData::~VertexPaintData()
{
FreeCache();
if (colordata) delete[] colordata;
if (nverts) delete[] nverts;
if (nvcverts) delete[] nvcverts;
nverts = NULL;
nvcverts = NULL;
colordata = NULL;
numColors = 0;
numnverts = 0;
numnvcverts = 0;
}
void VertexPaintData::SetCache(Mesh& m)
{
FreeCache();
mesh = new Mesh(m);
SynchVerts(m);
AllocColorData(mesh->getNumVerts());
}
void VertexPaintData::FreeCache()
{
if (mesh) delete mesh;
if (nverts) delete[] nverts;
if (nvcverts) delete[] nvcverts;
mesh = NULL;
nverts = NULL;
nvcverts = NULL;
numnverts = 0;
numnvcverts = 0;
}
Mesh* VertexPaintData::GetMesh()
{
return mesh;
}
NVert& VertexPaintData::GetNVert(int i)
{
static NVert nv;
if (numnverts > i)
return nverts[i];
else
return nv;
}
NVert& VertexPaintData::GetNVCVert(int i)
{
static NVert nv;
if (numnvcverts > i)
return nvcverts[i];
else
return nv;
}
COLORREF& VertexPaintData::GetColor(int i)
{
static COLORREF c = RGB(0, 0, 0);
if (numColors > i)
return colordata[i].color;
else
return c;
}
ColorData& VertexPaintData::GetColorData(int i)
{
static ColorData c;
if (numColors > i)
return colordata[i];
else
return c;
}
void VertexPaintData::SetColor(int i, float bary, COLORREF c, TComponent whichComp)
{
if (colordata && numColors > i)
{
// change color.
COLORREF oldColor = colordata[i].color;
int oldVal;
int editVal;
int newVal;
// Mask good component.
switch (whichComp)
{
case Red:
oldVal = GetRValue(colordata[i].color);
editVal = GetRValue(c);
break;
case Green:
oldVal = GetGValue(colordata[i].color);
editVal = GetGValue(c);
break;
case Blue:
oldVal = GetBValue(colordata[i].color);
editVal = GetBValue(c);
break;
}
// Blend Color component
// This color was set before !
float alpha = (1.0f - bary);
// Compute new value
newVal = (int)(alpha*oldVal + bary*editVal);
// Mask good component.
switch (whichComp)
{
case Red:
colordata[i].color = (RGB(newVal, 0, 0)) | (oldColor & RGB(0, 255, 255));
break;
case Green:
colordata[i].color = (RGB(0, newVal, 0)) | (oldColor & RGB(255, 0, 255));
break;
case Blue:
colordata[i].color = (RGB(0, 0, newVal)) | (oldColor & RGB(255, 255, 0));
break;
}
}
}
void VertexPaintData::SetColor(int i, const ColorData &c)
{
if (colordata && numColors > i)
{
colordata[i] = c;
}
}
int VertexPaintData::GetNumColors()
{
return numColors;
}
void VertexPaintData::AllocColorData(int numcols)
{
ColorData* newColorData;
// Colors already exist.
if (numColors == numcols)
return;
if (numColors > 0)
{
// If the new number of colors is bigger than what we have in the colordata array
if (numcols > numColors)
{
// Allocate a new color list and fill in as many as
// we have from the previous set
newColorData = new ColorData[numcols];
for (int i = 0; i < numcols; i++)
{
if (i < numColors)
{
newColorData[i] = colordata[i];
}
}
delete[] colordata;
colordata = newColorData;
numColors = numcols;
}
else
{
numColors = numcols;
}
}
else
{
// Allocate a complete new set of colors
numColors = numcols;
colordata = new ColorData[numColors];
}
}
LocalModData* VertexPaintData::Clone()
{
VertexPaintData* d = new VertexPaintData();
if (colordata)
{
d->colordata = new ColorData[numColors];
d->numColors = numColors;
for (int i = 0; i < numColors; i++)
{
d->colordata[i] = colordata[i];
}
}
if (nverts)
{
d->nverts = new NVert[numnverts];
for (int i = 0; i < numnverts; i++)
{
d->nverts[i] = nverts[i];
}
}
if (nvcverts)
{
d->nvcverts = new NVert[numnvcverts];
for (int i = 0; i < numnvcverts; i++)
{
d->nvcverts[i] = nvcverts[i];
}
}
return d;
}
void VertexPaintData::SynchVerts(Mesh &m)
{
if (mesh == NULL)
{
nlwarning("mesh == NULL");
return;
}
if (nverts)
delete[] nverts;
numnverts = m.getNumVerts();
nverts = new NVert[numnverts];
if (nvcverts)
delete[] nvcverts;
numnvcverts = m.getNumVertCol();
nvcverts = new NVert[numnvcverts];
for (int i = 0; i < mesh->getNumFaces(); i++)
{
// for each vertex of each face
for (int j = 0; j < 3; j++)
{
int iCur = nverts[mesh->faces[i].v[j]].faces.Count();
// Tell the vertex, which to which face it belongs and which
// of the three face v-indices corresponds to the vertex
nverts[mesh->faces[i].v[j]].faces.SetCount(iCur + 1);
nverts[mesh->faces[i].v[j]].whichVertex.SetCount(iCur + 1);
nverts[mesh->faces[i].v[j]].faces[iCur] = i;
nverts[mesh->faces[i].v[j]].whichVertex[iCur] = j;
if (mesh->vcFace)
{
// Do the same for texture vertices
iCur = nvcverts[mesh->vcFace[i].t[j]].faces.Count();
nvcverts[mesh->vcFace[i].t[j]].faces.SetCount(iCur + 1);
nvcverts[mesh->vcFace[i].t[j]].whichVertex.SetCount(iCur + 1);
nvcverts[mesh->vcFace[i].t[j]].faces[iCur] = i;
nvcverts[mesh->vcFace[i].t[j]].whichVertex[iCur] = j;
}
else
nlassert(0);
}
}
}
//***************************************************************************
//**
//** NVert
//**
//***************************************************************************
NVert::NVert()
{
faces.SetCount(0);
whichVertex.SetCount(0);
}
NVert& NVert::operator= (NVert &nvert)
{
faces = nvert.faces;
whichVertex = nvert.whichVertex;
return *this;
}
//***************************************************************************
//**
//** ColorData
//**
//***************************************************************************
ColorData::ColorData(DWORD col) : color(col)
{
}
ColorData::ColorData() : color(0)
{
}
//***************************************************************************
//**
//** VertexPaintRestore : public RestoreObj
//**
//***************************************************************************
VertexPaintRestore::VertexPaintRestore(VertexPaintData *pLocalData, VertexPaint *pVPaint)
: pMod(pVPaint), pPaintData(pLocalData), redoColordata(NULL)
{
colordata = new ColorData[pPaintData->numColors];
for (int i = 0; i < pPaintData->numColors; i++)
{
colordata[i] = pPaintData->colordata[i];
}
numcolors = pPaintData->numColors;
}
VertexPaintRestore::~VertexPaintRestore()
{
if (colordata)
delete[] colordata;
if (redoColordata)
delete[] redoColordata;
}
void VertexPaintRestore::Restore(int isUndo)
{
if (isUndo)
{
nlassert(pPaintData->colordata);
redoColordata = pPaintData->colordata;
redonumcolors = pPaintData->numColors;
pPaintData->colordata = colordata;
pPaintData->numColors = numcolors;
colordata = NULL;
pMod->NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
GetCOREInterface()->RedrawViews(GetCOREInterface()->GetTime());
}
}
void VertexPaintRestore::Redo()
{
nlassert(pPaintData->colordata);
colordata = pPaintData->colordata;
numcolors = pPaintData->numColors;
pPaintData->colordata = redoColordata;
pPaintData->numColors = redonumcolors;
redoColordata = NULL;
pMod->NotifyDependents(FOREVER, PART_VERTCOLOR, REFMSG_CHANGE);
GetCOREInterface()->RedrawViews(GetCOREInterface()->GetTime());
}
int VertexPaintRestore::Size()
{
int iSize = 0;
if (colordata)
iSize += sizeof(ColorData) * numcolors;
if (redoColordata)
iSize += sizeof(ColorData) * redonumcolors;
return iSize;
}