static void DoNotifyNodeUnHide(void *param, NotifyInfo *info)
{
	int code = info->intcode;
	INode *node = (INode*)info->callParam;
	if (Object* obj = node->GetObjectRef())
	{
		// Look for messages in network\Max.log
		// MAXScript_interface->Log()->LogEntry(SYSLOG_DEBUG, NO_DIALOG, "NifTools Max Plugin", 
		// 	"Entered DoNotifyNodeUnHide; node is -%s- and class ID is %ld\n", node->GetName(), obj->ClassID().PartA());

	   if (obj->ClassID() == BHKLISTOBJECT_CLASS_ID)
	   {
		   const int PB_MESHLIST = 1;
		   IParamBlock2* pblock2 = obj->GetParamBlockByID(0);
		   int nBlocks = pblock2->Count(PB_MESHLIST);
		   for (int i = 0;i < pblock2->Count(PB_MESHLIST); i++)
		   {
			   INode *tnode = nullptr;
			   pblock2->GetValue(PB_MESHLIST,0,tnode,FOREVER,i);	
			   if (tnode != nullptr)
			   {
				   tnode->Hide(FALSE);
			   }
		   }
	   }
	}
}
bool NifImporter::ImportMesh(ImpNode *node, TriObject *o, NiTriBasedGeomRef triGeom, NiTriBasedGeomDataRef triGeomData, vector<Triangle>& tris)
{
   Mesh& mesh = o->GetMesh();
   INode *tnode = node->GetINode();

   Matrix44 baseTM = (importBones) ? triGeom->GetLocalTransform() : triGeom->GetWorldTransform();
   node->SetTransform(0,TOMATRIX3(baseTM));  

   // Vertex info
   {
      int nVertices = triGeomData->GetVertexCount();
      vector<Vector3> vertices = triGeomData->GetVertices();
      mesh.setNumVerts(nVertices);
      for (int i=0; i < nVertices; ++i){
         Vector3 &v = vertices[i];
         mesh.verts[i].Set(v.x, v.y, v.z);
      }
   }
   // uv texture info
   {
      int nUVSet = triGeomData->GetUVSetCount();
      mesh.setNumMaps(nUVSet + 1, TRUE);
      int n = 0, j = 0;
      for (int j=0; j<nUVSet; j++){
         vector<TexCoord> texCoords = triGeomData->GetUVSet(j);
         n = texCoords.size();
         if (j == 0)
         {
            mesh.setNumTVerts(n, TRUE);
            for (int i=0; i<n; ++i) {
               TexCoord& texCoord = texCoords[i];
               mesh.tVerts[i].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
            }
         }
         mesh.setMapSupport (j + 1, TRUE);
         mesh.setNumMapVerts(j + 1, n, TRUE);
         if ( UVVert *tVerts = mesh.mapVerts(j+1) ) {
            for (int i=0; i<n; ++i) {
               TexCoord& texCoord = texCoords[i];
               tVerts[i].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
            }
         }
      }
   }
   // Triangles and texture vertices
   SetTriangles(mesh, tris);
   SetNormals(mesh, tris, triGeomData->GetNormals() );

   vector<Color4> cv = triGeomData->GetColors();
   ImportVertexColor(tnode, o, tris, cv, 0);

   if (Mtl* m = ImportMaterialAndTextures(node, triGeom))
   {
      gi->GetMaterialLibrary().Add(m);
      node->GetINode()->SetMtl(m);
   }

   if (removeDegenerateFaces)
      mesh.RemoveDegenerateFaces();
   if (removeIllegalFaces)
      mesh.RemoveIllegalFaces();
   if (enableSkinSupport)
      ImportSkin(node, triGeom);
   if (weldVertices)
	   WeldVertices(mesh);

   i->AddNodeToScene(node);   

   INode *inode = node->GetINode();
   inode->EvalWorldState(0);

   // attach child
   if (INode *parent = GetNode(triGeom->GetParent()))
      parent->AttachChild(inode, 1);

   inode->Hide(triGeom->GetVisibility() ? FALSE : TRUE);

   if (enableAutoSmooth){
      mesh.AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE);
   }

   RegisterNode(triGeom, inode);
   return true;
}
bool NifImporter::ImportMultipleGeometry(NiNodeRef parent, vector<NiTriBasedGeomRef>& glist)
{
   bool ok = true;
   if (glist.empty()) return false;

   ImpNode *node = i->CreateNode();
   if(!node) return false;

   INode *inode = node->GetINode();
   TriObject *triObject = CreateNewTriObject();
   node->Reference(triObject);

   string name = parent->GetName();
   node->SetName(wide(name).c_str());

   // Texture
   Mesh& mesh = triObject->GetMesh();

   vector< pair<int, int> > vert_range, tri_range;
   vector<Triangle> tris;
   vector<Vector3> verts;
   int submats = glist.size();

   // Build list of vertices and triangles.  Optional components like normals will be handled later.
   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr) {
      NiTriBasedGeomDataRef triGeomData = StaticCast<NiTriBasedGeomData>((*itr)->GetData());

      // Get verts and collapse local transform into them
      int nVertices = triGeomData->GetVertexCount();
      vector<Vector3> subverts = triGeomData->GetVertices();
      Matrix44 transform = (*itr)->GetLocalTransform();
      //Apply the transformations
      if (transform != Matrix44::IDENTITY) {
         for ( unsigned int i = 0; i < subverts.size(); ++i )
            subverts[i] = transform * subverts[i];
      }
      vert_range.push_back( pair<int,int>( verts.size(), verts.size() + subverts.size()) );
      verts.insert(verts.end(), subverts.begin(), subverts.end());

      vector<Triangle> subtris = triGeomData->GetTriangles();
      for (vector<Triangle>::iterator itr = subtris.begin(), end = subtris.end(); itr != end; ++itr) {
         (*itr).v1 += nVertices, (*itr).v2 += nVertices, (*itr).v3 += nVertices;
      }
      tri_range.push_back( pair<int,int>( tris.size(), tris.size() + subtris.size()) );
      tris.insert(tris.end(), subtris.begin(), subtris.end());
   }

   // Transform up-to-parent
   Matrix44 baseTM = (importBones) ? Matrix44::IDENTITY : parent->GetWorldTransform();
   node->SetTransform(0,TOMATRIX3(baseTM));  

   // Set vertices and triangles
   mesh.setNumVerts(verts.size());
   mesh.setNumTVerts(verts.size(), TRUE);
   for (int i=0, n=verts.size(); i < n; ++i){
      Vector3 &v = verts[i];
      mesh.verts[i].Set(v.x, v.y, v.z);
   }
   mesh.setNumFaces(tris.size());
   mesh.setNumTVFaces(tris.size());
   for (int submat=0; submat<submats; ++submat) {
      int t_start = tri_range[submat].first, t_end = tri_range[submat].second;
      for (int i=t_start; i<t_end; ++i) {
         Triangle& t = tris[i];
         Face& f = mesh.faces[i];
         f.setVerts(t.v1, t.v2, t.v3);
         f.Show();
         f.setEdgeVisFlags(EDGE_VIS, EDGE_VIS, EDGE_VIS);
         f.setMatID(-1);
         TVFace& tf = mesh.tvFace[i];
         tf.setTVerts(t.v1, t.v2, t.v3);
      }
   }
   mesh.buildNormals();
   bool bSpecNorms = false;

   MultiMtl *mtl = NULL;
   int igeom = 0;
   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr, ++igeom) 
   {
      NiTriBasedGeomDataRef triGeomData = StaticCast<NiTriBasedGeomData>((*itr)->GetData());

      int v_start = vert_range[igeom].first, v_end = vert_range[igeom].second;
      int t_start = tri_range[igeom].first, t_end = tri_range[igeom].second;

      // Normals
      vector<Vector3> subnorms = triGeomData->GetNormals();
      Matrix44 rotation = (*itr)->GetLocalTransform().GetRotation();
      if (rotation != Matrix44::IDENTITY) {
         for ( unsigned int i = 0; i < subnorms.size(); ++i )
            subnorms[i] = rotation * subnorms[i];
      }
      if (!subnorms.empty())
      {
#if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 5
         // Initialize normals if necessary
         if (!bSpecNorms) {
            bSpecNorms = true;
            mesh.SpecifyNormals();
            MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
            if (NULL != specNorms) {
               specNorms->BuildNormals();
               //specNorms->ClearAndFree();
               //specNorms->SetNumFaces(tris.size());
               //specNorms->SetNumNormals(n.size());
            }
         }
         MeshNormalSpec *specNorms = mesh.GetSpecifiedNormals();
         if (NULL != specNorms)
         {
            Point3* norms = specNorms->GetNormalArray();
            for (int i=0, n=subnorms.size(); i<n; i++){
               Vector3& v = subnorms[i];
               norms[i+v_start] = Point3(v.x, v.y, v.z);
            }
            //MeshNormalFace* pFaces = specNorms->GetFaceArray();
            //for (int i=0; i<tris.size(); i++){
            //   Triangle& tri = tris[i];
            //   MeshNormalFace& face = pFaces[i+t_start];
            //   face.SpecifyNormalID(0, tri.v1);
            //   face.SpecifyNormalID(1, tri.v2);
            //   face.SpecifyNormalID(2, tri.v3);
            //}
#if VERSION_3DSMAX > ((7000<<16)+(15<<8)+0) // Version 7+
			specNorms->SetAllExplicit(true);
#endif
            specNorms->CheckNormals();
         }
#endif
      }
      // uv texture info
      if (triGeomData->GetUVSetCount() > 0) {
         vector<TexCoord> texCoords = triGeomData->GetUVSet(0);
         for (int i=0, n = texCoords.size(); i<n; ++i) {
            TexCoord& texCoord = texCoords[i];
            mesh.tVerts[i+v_start].Set(texCoord.u, (flipUVTextures) ? 1.0f-texCoord.v : texCoord.v, 0);
         }
      }
      vector<Color4> cv = triGeomData->GetColors();
      ImportVertexColor(inode, triObject, tris, cv, v_start);

      if ( StdMat2* submtl = ImportMaterialAndTextures(node, (*itr)) )
      {
         if (mtl == NULL) {
            mtl = NewDefaultMultiMtl();
            gi->GetMaterialLibrary().Add(mtl);
            inode->SetMtl(mtl);
         }
         // SubMatIDs do not have to be contiguous so we just use the offset
         mtl->SetSubMtlAndName(igeom, submtl, submtl->GetName());
         for (int i=t_start; i<t_end; ++i)
            mesh.faces[i].setMatID(igeom);
      }
      if (enableSkinSupport)
         ImportSkin(node, (*itr));
   }

   this->i->AddNodeToScene(node);   

   inode = node->GetINode();
   inode->EvalWorldState(0);

   for (vector<NiTriBasedGeomRef>::iterator itr = glist.begin(), end = glist.end(); itr != end; ++itr) 
   {
      // attach child
      if (INode *parent = GetNode((*itr)->GetParent()))
         parent->AttachChild(inode, 1);
      inode->Hide((*itr)->GetVisibility() ? FALSE : TRUE);
   }
   if (removeDegenerateFaces)
      mesh.RemoveDegenerateFaces();
   if (removeIllegalFaces)
      mesh.RemoveIllegalFaces();
   if (weldVertices)
	   WeldVertices(mesh);
   if (enableAutoSmooth)
      mesh.AutoSmooth(TORAD(autoSmoothAngle), FALSE, FALSE);
   return ok;
}
Exemple #4
0
BOOL plComponentDlg::DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_INITDIALOG:
        fhDlg = hDlg;
        IAddComponentsRecur(GetDlgItem(hDlg, IDC_TREE), (plMaxNode*)GetCOREInterface()->GetRootNode());

        ICreateMenu();
        ICreateRightClickMenu();
        return TRUE;

    case WM_SIZING:
        IPositionControls((RECT*)lParam, wParam);
        return TRUE;

    case WM_ACTIVATE:
        if (LOWORD(wParam) == WA_INACTIVE)
            plMaxAccelerators::Enable();
        else
            plMaxAccelerators::Disable();
        return TRUE;

    case WM_COMMAND:
        if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDCANCEL)
        {
            ShowWindow(hDlg, SW_HIDE);
            fInterface->UnRegisterDlgWnd(hDlg);
            return TRUE;
        }
        else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ATTACH)
        {
            IAttachTreeSelection();
            return TRUE;
        }
        else if (HIWORD(wParam) == EN_KILLFOCUS && LOWORD(wParam) == IDC_COMMENTS)
        {
            IGetComment();
            return TRUE;
        }
        // "Refresh" menu item
        else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ID_REFRESH)
        {
            IRefreshTree();
            return TRUE;
        }
        // "Remove unused components" menu item
        else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == ID_REMOVE_UNUSED)
        {
            IRemoveUnusedComps();
            return TRUE;
        }
        // Item selected from 'New' menu
        else if (HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) >= MENU_ID_START)
        {
            ClassDesc *desc = plComponentMgr::Inst().Get(LOWORD(wParam)-MENU_ID_START);
            // If this is a component type (not a category)
            if (desc)
            {
                // Create an object of that type and a node to reference it
                Object *obj = (Object*)GetCOREInterface()->CreateInstance(desc->SuperClassID(), desc->ClassID());
                INode *node = GetCOREInterface()->CreateObjectNode(obj);

                plComponentBase *comp = (plComponentBase*)obj;
                node->Hide(!comp->AllowUnhide());
                node->Freeze(TRUE);

                // Add the new component to the tree
                HWND hTree = GetDlgItem(hDlg, IDC_TREE);
                HTREEITEM item = IAddComponent(hTree, (plMaxNode*)node);
                TreeView_SelectItem(hTree, item);
                TreeView_EnsureVisible(hTree, item);
            }
        }
        break;

    case WM_NOTIFY:
        NMHDR *nmhdr = (NMHDR*)lParam;
        if (nmhdr->idFrom == IDC_TREE)
        {
            switch (nmhdr->code)
            {
            case TVN_SELCHANGED:
                {
                    NMTREEVIEW *tv = (NMTREEVIEW*)lParam;

                    IGetComment();

                    bool isComponent = IIsComponent(tv->itemNew.lParam);

                    // If the new selection is a component, enable the attach button and comment field
                    EnableWindow(GetDlgItem(hDlg, IDC_ATTACH), isComponent);
                    SendDlgItemMessage(hDlg, IDC_COMMENTS, EM_SETREADONLY, !isComponent, 0);

                    if (isComponent)
                    {
                        fCommentNode = (plMaxNode*)tv->itemNew.lParam;
                        
                        TSTR buf;
                        fCommentNode->GetUserPropBuffer(buf);
                        SetDlgItemText(hDlg, IDC_COMMENTS, buf);
                    }
                    else
                    {
                        fCommentNode = nil;
                        SetDlgItemText(hDlg, IDC_COMMENTS, "");
                    }

                    return TRUE;
                }
                break;

            case TVN_BEGINLABELEDIT:
                // If this isn't a component, don't allow the edit
                if (!IIsComponent(((NMTVDISPINFO*)lParam)->item.lParam))
                {
                    SetWindowLong(hDlg, DWL_MSGRESULT, TRUE);
                    return TRUE;
                }

                // The edit box this creates kills the focus on our window, causing
                // accelerators to be enabled.  Add an extra disable to counteract that.
                plMaxAccelerators::Disable();

                return TRUE;

            // Finishing changing the name of a component
            case TVN_ENDLABELEDIT:
                {
                    NMTVDISPINFO *di = (NMTVDISPINFO*)lParam;
                    char* text = di->item.pszText;
                    // If the name was changed...
                    if (text && *text != '\0')
                    {
                        // Update the name of the node
                        plMaxNode *node = IGetTreeSelection();
                        node->SetName(text);

                        // Update the name in the panel too
                        if (plComponentUtil::Instance().IsOpen())
                            plComponentUtil::Instance().IUpdateNodeName(node);

                        // Make sure Max knows the file was changed
                        SetSaveRequiredFlag();

                        // Return true to keep the changes
                        SetWindowLong(hDlg, DWL_MSGRESULT, TRUE);
                    }

                    plMaxAccelerators::Enable();
                }
                return TRUE;

            // User double-clicked.  Select the objects the selected component is attached to.
            case NM_DBLCLK:
                ISelectTreeSelection();
                return TRUE;

            case NM_RCLICK:
                IOpenRightClickMenu();
                return TRUE;
                
            case TVN_KEYDOWN:
                // User pressed delete
                if (((NMTVKEYDOWN*)lParam)->wVKey == VK_DELETE)
                {
                    IDeleteComponent(IGetTreeSelection());
                    return TRUE;
                }
                break;
            }
        }
        break;
    }

    return FALSE;
}
void NifImporter::ImportBones(NiNodeRef node, bool recurse)
{
   try 
   {
      if (uncontrolledDummies)
         BuildControllerRefList(node, ctrlCount);

      string name = node->GetName();

      vector<NiAVObjectRef> children = node->GetChildren();
      vector<NiNodeRef> childNodes = DynamicCast<NiNode>(children);

      NiAVObject::CollisionType cType = node->GetCollisionMode();
      if (children.empty() && name == "Bounding Box")
         return;

      // Do all node manipulations here
      NiNodeRef parent = node->GetParent();
      string parentname = (parent ? parent->GetName() : "");
      Matrix44 m4 = node->GetWorldTransform();

      // Check for Prn strings and change parent if necessary
      if (supportPrnStrings) {
         list<NiStringExtraDataRef> strings = DynamicCast<NiStringExtraData>(node->GetExtraData());
         for (list<NiStringExtraDataRef>::iterator itr = strings.begin(); itr != strings.end(); ++itr){
            if (strmatch((*itr)->GetName(), "Prn")) {
               parentname = (*itr)->GetData();
               if (INode *pn = gi->GetINodeByName(parentname.c_str())){
                  // Apparently Heads tend to need to be rotated 90 degrees on import for 
                  if (!rotate90Degrees.empty() && wildmatch(rotate90Degrees, parentname)) {
                     m4 *= TOMATRIX4(RotateYMatrix(TORAD(90)));
                  }
                  m4 *= TOMATRIX4(pn->GetObjTMAfterWSM(0, NULL));
               }
            }
         }
      }

      float len = node->GetLocalTranslation().Magnitude();

      // Remove NonAccum nodes and merge into primary bone
      if (mergeNonAccum && wildmatch("* NonAccum", name) && parent)
      {
         string realname = name.substr(0, name.length() - 9);
         if (strmatch(realname, parent->GetName()))
         {
            Matrix44 tm = parent->GetLocalTransform() * node->GetLocalTransform();
            name = realname;
            len += tm.GetTranslation().Magnitude();
			parent = parent->GetParent();
         }
      }

      PosRotScale prs = prsDefault;
      Vector3 pos; Matrix33 rot; float scale;
      m4.Decompose(pos, rot, scale);

      Matrix3 im = TOMATRIX3(m4);
      Point3 p = im.GetTrans();
      Quat q(im);
      //q.Normalize();
      Vector3 ppos;
      Point3 zAxis(0,0,0);
      bool hasChildren = !children.empty();
      if (hasChildren) {
         float len = 0.0f;
         for (vector<NiAVObjectRef>::iterator itr=children.begin(), end = children.end(); itr != end; ++itr) {
            len += GetObjectLength(*itr);
         }
         len /= float(children.size());
         ppos = pos + Vector3(len, 0.0f, 0.0f); // just really need magnitude as rotation will take care of positioning
      }
      else if (parent)
      {
         ppos = pos + Vector3(len/3.0f, 0.0f, 0.0f);
      }
      Point3 pp(ppos.x, ppos.y, ppos.z);

      Point3 qp = TORAD(TOEULER(im));


      INode *bone = NULL;
	  if (!doNotReuseExistingBones) // Games like BC3 reuse the same bone names
	  {
		  bone = FindNode(node);
		  if (bone == NULL) 
			  bone = gi->GetINodeByName(name.c_str());
	  }
      if (bone)
      {
         // Is there a better way of "Affect Pivot Only" behaviors?
         INode *pinode = bone->GetParentNode();
         if (pinode)
            bone->Detach(0,1);
         PosRotScaleNode(bone, p, q, scale, prs);
         if (pinode)
            pinode->AttachChild(bone, 1);
      }
      else
      {
         bool isDummy = ( (uncontrolledDummies && !HasControllerRef(ctrlCount, name))
                     || (!dummyNodeMatches.empty() && wildmatch(dummyNodeMatches, name))
                     || (convertBillboardsToDummyNodes && node->IsDerivedType(NiBillboardNode::TYPE))
                      );
         if (wildmatch("Camera*", name)) {
            if (enableCameras) {
               if (bone = CreateCamera(name)) {
                  PosRotScaleNode(bone, p, q, scale, prs);
                  bone->Hide(node->GetVisibility() ? FALSE : TRUE);
               }
            }
         }else if (isDummy && createNubsForBones)
            bone = CreateHelper(name, p);
         else if (bone = CreateBone(name, p, pp, zAxis))
         {
            PosRotScaleNode(bone, p, q, scale, prs);
            bone->Hide(node->GetVisibility() ? FALSE : TRUE);
         }
         if (bone)
         {
            if (!parentname.empty())
            {
               if (mergeNonAccum && wildmatch("* NonAccum", parentname)) {
                  parentname = parentname.substr(0, parentname.length() - 9);
               }
               if (INode *pn = gi->GetINodeByName(parentname.c_str()))
                  pn->AttachChild(bone, 1);
            }
			RegisterNode(node, bone);
         }
      }
      // Import UPB
      if (bone) ImportUPB(bone, node);

      // Import Havok Collision Data surrounding node,  
	  //   unfortunately this causes double import of collision so I'm disabling it for now.
	  if (enableCollision && node->GetParent()) {
		ImportCollision(node);
	  }

      if (bone && recurse)
      {
         ImportBones(childNodes);
      }
   }
   catch( exception & e ) 
   {
      e=e;
   }
   catch( ... ) 
   {
   }
}