/********************************************************************** *< 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(¤tVersion, 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(¤tVersion, 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; }