/********************************************************************** *< 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 BOOL CALLBACK VertexPaintDlgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { int numPoints; VertexPaint *mod = (VertexPaint*)GetWindowLong(hWnd,GWL_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; SetWindowLong(hWnd,GWL_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 mod = GetWindowLong(hPanel,GWL_USERDATA); if (mod) { ((VertexPaint*)mod)->PaletteButton(hwnd); } } break; case WM_DESTROY: SetWindowLong(hwnd, GWL_WNDPROC, (LONG) 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; fgetNumFaces(); 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<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; iGetShowEndResult() ? 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; ilocalData; 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( Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message) { 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; iGetColorData(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; iRead(&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; iSetColor(palColors[i]); ReleaseIColorSwatch(c); } } void VertexPaint::SavePalettes() { IColorSwatch* c; for (int i=0; iGetColor(); 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=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; mcilocalData) 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; mcilocalData) { VertexPaintData* d = (VertexPaintData*)mc->localData; Mesh* mesh = d->GetMesh(); if (mesh && mesh->vertCol) { // For all faces of the mesh for(int fi=0; figetNumFaces(); 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; mcilocalData) 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; mcilocalData) { 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; figetNumFaces(); 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.yyMaxi?p.y:yMaxi; } } // 2nd, For all faces of the mesh, fill with gradient for(fi=0; figetNumFaces(); 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; icolordata = new ColorData[numColors]; d->numColors = numColors; for (int i=0; icolordata[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; }