/********************************************************************** *< FILE: CvObject.cpp DESCRIPTION: 3dStudio Collision object implementation CREATED BY: jkyle HISTORY: *> Copyright (c) 1997, All Rights Reserved. **********************************************************************/ #include "stdafx.h" #include "CvObject.h" #include "polyshp.h" #include "mw4.hpp" #include #include #pragma pack(push,8) Stuff::OBB g_obbdeleteme; #define MIN_ZOOM 0.0001f #define RU_UPDATE WM_USER + 666 #define NUMVERTS 7 static Point3 arrow_side[7]= { Point3( 0.000000, -1.000000 , 0.00000), Point3( 0.000000, -0.500000 , 0.40000), Point3( 0.000000, -0.500000, 0.20000), Point3( 0.000000, -0.000000, 0.20000), Point3( 0.000000, -0.000000, 0.00000), Point3( 0.000000, -0.500000, 0.00000), Point3( 0.000000, -0.500000, 0.00000) }; static Point3 arrow_flat[7]= { Point3( -0.00000, -1.000000, 0.0), Point3( 0.400000, -0.50000, 0.0), Point3( 0.200000, -0.50000, 0.0), Point3( 0.200000, -0.0, 0.0), Point3( -0.200000, -0.0, 0.0), Point3( -0.200000, -0.50000, 0.0), Point3( -0.400000, -0.50000, 0.0) }; #define PARAMDESC_LENGTH 1 static ParamUIDesc descParam[] = { // Index 0 is the material list // Spinner // 3 points (x,y,z_ ParamUIDesc( CV_SIZE,EDITTYPE_FLOAT, IDC_EDIT_X,IDC_SPIN_X, IDC_EDIT_Y,IDC_SPIN_Y, IDC_EDIT_Z,IDC_SPIN_Z, 0.0,2000.0,1.0, defaultDim) }; /* ParamUIDesc( 2,EDITTYPE_FLOAT, IDC_OBB_EDIT_LOCALX2,IDC_OBB_SPIN_LOCALX2, IDC_OBB_EDIT_LOCALY2,IDC_OBB_SPIN_LOCALY2, IDC_OBB_EDIT_LOCALZ2,IDC_OBB_SPIN_LOCALZ2, -200.0,200.0,1.0, defaultDim), ParamUIDesc( 3,EDITTYPE_FLOAT, IDC_OBB_EDIT_LOCALRADIUS,IDC_OBB_SPIN_LOCALRADIUS, 0.0,200.0,1.0,defaultDim) ParamUIDesc( 3,EDITTYPE_FLOAT, IDC_OBB_EDIT_WORLDX,IDC_OBB_SPIN_WORLDX, IDC_OBB_EDIT_WORLDY,IDC_OBB_SPIN_WORLDY, IDC_OBB_EDIT_WORLDZ,IDC_OBB_SPIN_WORLDZ, -200.0,200.0,1.0, defaultDim), ParamUIDesc( 4,EDITTYPE_FLOAT, IDC_OBB_EDIT_WORLDX2,IDC_OBB_SPIN_WORLDX2, IDC_OBB_EDIT_WORLDY2,IDC_OBB_SPIN_WORLDY2, IDC_OBB_EDIT_WORLDZ2,IDC_OBB_SPIN_WORLDZ2, -200.0,200.0,1.0, defaultDim), ParamUIDesc( 5,EDITTYPE_FLOAT, IDC_OBB_EDIT_WORLDRADIUS,IDC_OBB_SPIN_WORLDRADIUS, 0.0,200.0,1.0,defaultDim), /*ParamUIDesc( 6,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK1), ParamUIDesc( 7,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK2), ParamUIDesc( 8,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK3), ParamUIDesc( 9,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK4), ParamUIDesc( 10,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK5), ParamUIDesc( 11,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK6), ParamUIDesc( 12,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK7), ParamUIDesc( 13,TYPE_SINGLECHEKBOX,IDC_OBB_CHECK8), */ /* ParamUIDesc( 6,TYPE_SINGLECHEKBOX,(int *)&descCheckID,8) }; */ #define PARAMBLOCK_LENGTH 2 //TODO: Add ParamBlockDescID's for the various parameters static ParamBlockDescID descVer1[] = { { TYPE_INT, NULL, FALSE, 0}, // Material flags { TYPE_POINT3, NULL, FALSE, 1} }; // #define CURRENT_DESCRIPTOR descVer1 //Not used #define CURRENT_VERSION 1 // class variable for point class. HWND CvObject::m_hParams = NULL; IObjParam *CvObject::m_iObjParams; IParamMap *CvObject::m_pmapParam = NULL; class MyParamMapDlgProc : public ParamMapUserDlgProc { virtual BOOL DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam); virtual void DeleteThis(); virtual void Update(TimeValue t) {}; }; static MyParamMapDlgProc g_myParamMapDlgProc; MyParamMapDlgProc::DlgProc(TimeValue t,IParamMap *map,HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { switch (msg) { case WM_COMMAND: { //Handle Panel's controls HWND hwndCtrl = (HWND)lParam; switch (LOWORD(wParam)) { case IDC_LIST_MATERIAL: { switch (HIWORD(wParam)) { case CBN_SELCHANGE: { int iSel = SendMessage(hwndCtrl,LB_GETCURSEL,0,0); int data = SendMessage(hwndCtrl,LB_GETITEMDATA,iSel,0); int iVal; map->GetParamBlock()->GetValue(CV_MATERIAL,0,iVal,FOREVER); map->GetParamBlock()->SetValue(CV_MATERIAL,t,data | (iVal & Adept::CollisionVolume::e_GoodEnough) ); break; } } break; } case IDC_CHECK_GOODENUF: { switch (HIWORD(wParam)) { case BN_CLICKED: { int check = SendMessage(hwndCtrl,BM_GETCHECK,0,0); int iVal; map->GetParamBlock()->GetValue(CV_MATERIAL,0,iVal,FOREVER); iVal &= ~Adept::CollisionVolume::e_GoodEnough; map->GetParamBlock()->SetValue(CV_MATERIAL,t,iVal | (check?Adept::CollisionVolume::e_GoodEnough:0) ); break; } } break; } } } } return TRUE; } void MyParamMapDlgProc::DeleteThis() { } /* BOOL CALLBACK PointParamProc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam) { CvObject *po = (CvObject*)GetWindowLong(hWnd,GWL_USERDATA); if (!po && msg!=WM_INITDIALOG) return FALSE; return TRUE; } */ Animatable* CvObject::SubAnim(int i) { switch (i) { case 0: return m_pblock; // Parameter block default: return NULL; } } TSTR CvObject::SubAnimName(int i) { switch (i) { case 0: return TSTR(_T("Parameters")); default: return TSTR(_T("")); } } void CvObject::BeginEditParams( IObjParam *ip, ULONG flags,Animatable *prev) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); HINSTANCE loc_hInstance = AfxGetResourceHandle (); m_iObjParams = ip; if (m_pmapParam) { // Left over m_pmapParam->SetParamBlock(m_pblock); } else { // Gotta make a new one. m_pmapParam = CreateCPParamMap( descParam,PARAMDESC_LENGTH, m_pblock, ip, loc_hInstance, MAKEINTRESOURCE(IDD_CV_PANEL), GetString(IDS_PARAMS), 0); } m_pmapParam->SetUserDlgProc(&g_myParamMapDlgProc); HWND hList = GetDlgItem(m_pmapParam->GetHWnd(),IDC_LIST_MATERIAL); if (hList) { int iVal; m_pblock->GetValue(CV_MATERIAL,m_iObjParams->GetTime(),iVal,FOREVER); int iCheck = iVal & (Adept::CollisionVolume::e_GoodEnough); iVal &= ~Adept::CollisionVolume::e_GoodEnough; for (int x=0;xGetHWnd(),IDC_CHECK_GOODENUF); SendMessage(hCheck,BM_SETCHECK,BST_CHECKED,0); } } } void CvObject::EndEditParams(IObjParam *ip, ULONG flags,Animatable *next) { if (flags&END_EDIT_REMOVEUI ) { DestroyCPParamMap(m_pmapParam); m_pmapParam = NULL; } m_iObjParams = NULL; } ObjectState CvObject::Eval(TimeValue time) { return ObjectState(this); } #define BOOL_CONTROL_CLASS_ID Class_ID(0x984b8d27,0x938f3e43) CvObject::CvObject() { m_suspendSnap = FALSE; m_pblock = NULL; // m_pParent = NULL; //m_pNode = NULL; MakeRefByID( FOREVER, 0, CreateParameterBlock( descVer1, PARAMBLOCK_LENGTH, CURRENT_VERSION ) ); // MakeRefByID( FOREVER, 0, CreateParameterBlock( NULL, 0, CURRENT_VERSION ) ); } RefTargetHandle CvObject::GetReference(int i) { if (i==0) return m_pblock; return NULL; } // This methods sets the ith reference - there are two. void CvObject::SetReference(int i, RefTargetHandle rtarg) { if (i==0) { m_pblock = (IParamBlock *)rtarg; } } int CvObjectCreateCallBack::proc(ViewExp *vpt,int msg, int point, int flags, IPoint2 m, Matrix3& mat ) { switch (msg) { case MOUSE_POINT: case MOUSE_MOVE: { switch(point) { case 0: m_ob->m_suspendSnap = TRUE; m_p0 = vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE); mat.SetTrans(m_p0); break; case 1: // mat.SetTrans(vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE)); m_p1 = vpt->SnapPoint(m,m,NULL,SNAP_IN_PLANE); // m_ob->m_pblock->SetValue(PB_SITE_SCALE,0,Length(m_p1-m_p0)); if (msg==MOUSE_POINT) { m_ob->m_suspendSnap = FALSE; return 0; } break; } break; } case MOUSE_ABORT: return CREATE_ABORT; case WM_COMMAND: { // int x=1; break; } default: { // int x; // x++; } } return 1; } static CvObjectCreateCallBack cvObjectCreateCB; CreateMouseCallBack* CvObject::GetCreateMouseCallBack() { cvObjectCreateCB.SetObj(this); return(&cvObjectCreateCB); } RefTargetHandle CvObject::Clone(RemapDir& remap) { CvObject* newob = new CvObject(); // newob->triggerCount = triggerCount; // newob->siteScale = siteScale; newob->ReplaceReference(0, m_pblock->Clone(remap)); return(newob); } RefResult CvObject::NotifyRefChanged( Interval changeInt, RefTargetHandle hTarget, PartID& partID, RefMessage message) { switch (message) { /* case REFMSG_TARGET_DELETED: { DeleteReference(FindRef(hTarget)); break; } case REFMSG_NODE_LINK: { if (m_pNode) { m_pParent = m_pNode->GetParentNode(); DeleteReference(FindRef(hTarget)); } break; }*/ case REFMSG_CHANGE: { if (m_pblock) { if (m_iObjParams) { // m_pblock->GetValue(PB_Cv_SCALE,m_iObjParams->GetTime(),siteScale, FOREVER); } else { // m_pblock->GetValue(PB_SITE_SCALE, 0,siteScale, FOREVER); } } if (m_pmapParam) m_pmapParam->Invalidate(); NotifyDependents(FOREVER,PART_OBJ,REFMSG_CHANGE); if (m_iObjParams) m_iObjParams->RedrawViews(m_iObjParams->GetTime()); break; } case REFMSG_GET_PARAM_DIM: { GetParamDim *gpd = (GetParamDim*)partID; switch (gpd->index) { case 0: default: gpd->dim = defaultDim; break; } return REF_STOP; } case REFMSG_GET_PARAM_NAME: { GetParamName *gpn = (GetParamName*)partID; return REF_STOP; } } return REF_SUCCEED; } //#define OBB_MATERIALCHUNK 0x0130 //#define SITE_SCALE_CHUNK 0x0110 //#define TRIGGER_CHUNK 0x0120 // Don't need to save anything except for TM because it is a unit box IOResult CvObject::Load(ILoad *iload) { // CvStruct cv; /* ULONG nb; IOResult res = IO_OK; while (IO_OK==(res=iload->OpenChunk())) { switch (iload->CurChunkID()) { case OBB_CHUNK: { res = iload->Read(&m_cvBox,sizeof(m_cvBox),&nb); } } res = iload->CloseChunk(); if (res!=IO_OK) { return res; } } */ return IO_OK; } IOResult CvObject::Save(ISave *isave) { // CvStruct cv; /*ULONG nb; isave->BeginChunk(OBB_CHUNK); isave->Write(&m_cvBox,sizeof(m_cvBox),&nb); isave->EndChunk();*/ return IO_OK; } void CvObject::SetExtendedDisplay(int flags) { m_extDispFlags = flags; } void CvObject::GetLocalBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) { Matrix3 tm(1); tm.SetTrans(inode->GetObjectTM(t).GetTrans()); Point3 vec; if (GetParamBlock()->GetValue(CV_SIZE,t,vec,FOREVER)) { box = GetAxisBox(vpt,tm,vec, TRUE); } } void CvObject::GetWorldBoundBox(TimeValue t, INode* inode, ViewExp* vpt, Box3& box ) { Matrix3 tm; tm = inode->GetObjectTM(t); if(!(m_extDispFlags & EXT_DISP_ZOOM_EXT)) { Point3 vec; if (GetParamBlock()->GetValue(CV_SIZE,t,vec,FOREVER)) { box = GetAxisBox(vpt,tm,vec, FALSE); } } else { box = Box3(tm.GetTrans(), tm.GetTrans()); } } // From BaseObject int CvObject::HitTest(TimeValue t, INode *inode, int type, int crossing, int flags, IPoint2 *p, ViewExp *vpt) { Matrix3 tm(1); HitRegion hitRegion; DWORD savedLimits; Point3 pt(0,0,0); GraphicsWindow *gw = vpt->getGW(); tm = inode->GetObjectTM(t); MakeHitRegion(hitRegion, type, crossing, 4, p); gw->setRndLimits(((savedLimits = gw->getRndLimits())|GW_PICK)&~GW_ILLUM); gw->setHitRegion(&hitRegion); gw->clearHitCode(); DrawAxis(vpt,tm,1.0,inode->Selected(),inode->IsFrozen()); Point3 vec; if (GetParamBlock()->GetValue(CV_SIZE,t,vec,FOREVER)) { if (LengthSquared(vec)<0.00001) { vec = Point3(1.0,1.0,1.0); } vec = vec * 0.5f; Box3 b(vec*-1,vec); DrawBox(vpt->getGW(),b); } vpt->getGW()->setTransform(tm); vpt->getGW()->marker(&pt,X_MRKR); gw->setRndLimits(savedLimits); if((hitRegion.type != POINT_RGN) && !hitRegion.crossing) { return TRUE; } return gw->checkHitCode(); } void CvObject::Snap(TimeValue t, INode* inode, SnapInfo *snap, IPoint2 *p, ViewExp *vpt) { // if(m_suspendSnap) // { // return; // } Matrix3 tm = inode->GetObjectTM(t); GraphicsWindow *gw = vpt->getGW(); gw->setTransform(tm); Matrix3 invPlane = Inverse(snap->plane); // Check for upside-down coordinate system in viewport float ybias = (float)gw->getWinSizeY() - 1.0f; // Make sure the vertex priority is active and at least as important as the best snap so far if(snap->vertPriority > 0 && snap->vertPriority <= snap->priority) { Point2 fp = Point2((float)p->x, (float)p->y); Point3 screen3; Point2 screen2; Point3 thePoint(0,0,0); // If constrained to the plane, make sure this point is in it! if(snap->snapType == SNAP_2D || snap->flags & SNAP_IN_PLANE) { Point3 test = thePoint * tm * invPlane; if(fabs(test.z) > 0.0001) // Is it in the plane (within reason)? { return; } } //gw->transPointFWin(&thePoint,&screen3); //this is for MAX 1.2 gw->transPoint(&thePoint, &screen3); screen3.y = ybias - screen3.y; screen2.x = screen3.x; screen2.y = screen3.y; // Are we within the snap radius? int len = (int)Length(screen2 - fp); if(len <= snap->strength) { // Is this priority better than the best so far? if(snap->vertPriority < snap->priority) { snap->priority = snap->vertPriority; snap->bestWorld = thePoint * tm; snap->bestScreen = screen2; snap->bestDist = len; } else if(len < snap->bestDist) { snap->priority = snap->vertPriority; snap->bestWorld = thePoint * tm; snap->bestScreen = screen2; snap->bestDist = len; } } } } int CvObject::Display(TimeValue t, INode* inode, ViewExp *vpt, int flags) { Matrix3 tm = inode->GetObjectTM(t); Point3 pt(0,0,0); vpt->getGW()->setTransform(tm); Point3 vec; DrawAxis(vpt,tm,1.0,inode->Selected(),inode->IsFrozen()); if (GetParamBlock()->GetValue(CV_SIZE,t,vec,FOREVER)) { if (LengthSquared(vec)<0.00001) { vec = Point3(1.0,1.0,1.0); } vec = vec * 0.5f; Box3 b(vec*-1,vec); DrawBox(vpt->getGW(),b); } if(!inode->IsFrozen()) { vpt->getGW()->setColor(LINE_COLOR,1.0f,0.9f,0.0f); } vpt->getGW()->marker(&pt,X_MRKR); return(0); } /*--------------------------------------------------------------------*/ // // Stole this from scene.cpp // Probably couldn't hurt to make an API... // // #define ZFACT (float).005; #define AXIS_COLOR 0.4f,0.4f,0.4f #define SELAXIS_COLOR 1.0f,1.0f,1.0f void CvObject::DrawAxis( ViewExp *vpt, const Matrix3 &tm, float length, BOOL sel, BOOL frozen ) { Matrix3 tmn = tm; int limits; vpt->getGW()->setTransform( tmn ); limits = vpt->getGW()->getRndLimits(); if (sel) { vpt->getGW()->setColor( TEXT_COLOR, SELAXIS_COLOR ); vpt->getGW()->setColor( LINE_COLOR, SELAXIS_COLOR ); } else if (!frozen) { vpt->getGW()->setColor( TEXT_COLOR, AXIS_COLOR ); vpt->getGW()->setColor( LINE_COLOR, AXIS_COLOR ); } vpt->getGW()->setRndLimits( limits ); } void CvObject::DrawBox(GraphicsWindow *gw, Box3 &box) { Point3 pt[5]; pt[0] = box[0]; pt[1] = box[1]; pt[2] = box[3]; pt[3] = box[2]; gw->polyline(4, pt, NULL, NULL, 1, NULL); pt[0] = box[4]; pt[1] = box[5]; pt[2] = box[7]; pt[3] = box[6]; gw->polyline(4, pt, NULL, NULL, 1, NULL); pt[0] = box[0]; pt[1] = box[4]; gw->polyline(2, pt, NULL, NULL, 0, NULL); pt[0] = box[1]; pt[1] = box[5]; gw->polyline(2, pt, NULL, NULL, 0, NULL); pt[0] = box[2]; pt[1] = box[6]; gw->polyline(2, pt, NULL, NULL, 0, NULL); pt[0] = box[3]; pt[1] = box[7]; gw->polyline(2, pt, NULL, NULL, 0, NULL); } Box3 CvObject::GetAxisBox(ViewExp *vpt, const Matrix3 &tm,Point3 vec,int resetTM) { Matrix3 tmn = tm; float zoom; // Get width of viewport in world units: --DS zoom = vpt->GetScreenScaleFactor(tmn.GetTrans())*ZFACT; if (zoom < MIN_ZOOM) zoom = 1.0f; if(resetTM) { tmn.IdentityMatrix(); } Box3 box; box += Point3(vec.x*0.5f, 0.0f, 0.0f) *tm; box += Point3(0.0f, vec.y*0.5f, 0.0f) *tm; box += Point3(0.0f, 0.0f, vec.z*0.5f) *tm; box += Point3(-vec.x*0.5f, 0.0f, 0.0f) *tm; box += Point3(0.0f, -vec.y*0.5f, 0.0f) *tm; box += Point3(0.0f, 0.0f, -vec.z*0.5f) *tm; box.EnlargeBy(10.0f/zoom); return box; } /*void CvObject::CalcLocalBoundBox(int nSamples,ViewExp *vpt,Box3& box) // nSamples must be at least 1 { // Calculate the bounding box of the parent if (m_pParent) { Object *pObject = m_pParent->GetObjectRef(); if (pObject) { //Interval iv = m_iObjParams->GetAnimRange(); TimeValue tStart,tEnd,tInc; tStart = GetAnimStart(); tEnd = GetAnimEnd(); if (nSamples<1) nSamples = 1; tInc = (tEnd - tStart) / nSamples; pObject->GetLocalBoundBox(tStart,m_pParent,vpt,box); for (TimeValue t = (tStart+tInc);t<=tEnd;t+=tInc) { Box3 boxnew; pObject->GetLocalBoundBox(t,m_pParent,vpt,boxnew); box+=boxnew; } } } } void CvObject::CalcOBBChildren(INode *pNode) { /* if (pNode) { char *pName = pNode->GetName(); if (0 == strncmp(pName,"cv_",3)) { Class_ID c1 = CVOBJECT_CLASS_ID; Class_ID c2 = pNode->GetObjectRef()->ClassID(); if (pNode != m_pNode) { MakeRefByID( FOREVER, 2, pNode); Box3 box; pNode->GetObjectRef()->GetLocalBoundBox(0,pNode,NULL,box); m_cvBox+=box; } } else { for (int x = 0;xNumberOfChildren();x++) { INode *pChild = pNode->GetChildNode(x); CalcOBBChildren(pChild); } } }*/ //} #pragma pack(pop)