void PivotSnap::Snap(Object* pobj, IPoint2 *p, TimeValue t) { // This snap computes the bounding box points of a node as // well as the pivot point //local copy of the cursor position Point2 fp = Point2((float)p->x, (float)p->y); //In this snap mode we actually need to get a pointer to the node so that we // can check for WSM's and compute the pivot point INode *inode = theman->GetNode(); Matrix3 atm(1); //This will hold the nodes tm before WSMs //See if this guys has any spacewarps applied BOOL wsm = (BOOL) inode->GetProperty(PROPID_HAS_WSM); //If it does then we'll need to get a meaningful tm as follows if(wsm) atm = inode->GetObjTMBeforeWSM(t); //get the node's bounding box Box3 box; box.Init(); pobj->GetDeformBBox(t, box, NULL ); if(EssentiallyEmpty(box)) pobj->GetLocalBoundBox(t, inode, theman->GetVpt() , box); //We need a hitmesh which shows the bounding box of the node //This automatic variable gets passed to the hitmesh copy constructor // in every case HitMesh thehitmesh, *phitmesh; thehitmesh.setNumVerts(8); for(int jj = 0;jj<8;++jj) thehitmesh.setVert(jj,box[jj]); BOOL got_one= FALSE; //Compute all the hit point candidates if( GetActive(PIV_SUB)) { got_one = FALSE; Point3 *pivpt; //JH 10/02/01 //DID 296059 Matrix3 tm(1); Point3 pos = inode->GetObjOffsetPos(); tm.PreTranslate(pos); Quat quat = inode->GetObjOffsetRot(); PreRotateMatrix(tm, quat); ScaleValue scale = inode->GetObjOffsetScale(); ApplyScaling(tm, scale); Matrix3 InvTm = Inverse(tm); //JH 10/02/01 //atm contains the identity normally, or the node TM before spacewarps, when space warps are applied //We're computing a point relative to the node TM, so in the former case the inverse of //the object offset pos is what we want. In the latter (when the node TM is identtity, we must add //in the node TM before WSM. pivpt = new Point3(atm.GetTrans() + InvTm.GetTrans()); //Make a hitmesh phitmesh = new HitMesh(thehitmesh); //now register a hit with the osnap manager theman->RecordHit(new OsnapHit(*pivpt, this, PIV_SUB, phitmesh)); } if( GetActive(BBOX_SUB)) { //set up our highlight mesh for(int ii = 0;ii<8;++ii) { phitmesh = new HitMesh(thehitmesh); theman->RecordHit(new OsnapHit(box[ii], this, BBOX_SUB, phitmesh)); } } };
void PatchDeformPW::ModifyObject(TimeValue t, ModContext &mc, ObjectState * os, INode *incnode) { Interval iv = FOREVER; //TODO: Add the code for actually modifying the object //check is local data if not create it if (mc.localData == NULL) { LocalPatchData *localData = new LocalPatchData(); mc.localData = localData; } LocalPatchData *localData = (LocalPatchData *)mc.localData; if (localData == NULL ) return; if (localData->selfNode == NULL) { localData->selfNode = GetNodeFromModContext(localData); } //check if patch count has changed if so update our uv space //if rebuild then INode *node = NULL; pblock->GetValue(pb_patch,t,node,iv); if (node == NULL) { os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); return; } ObjectState patchos = node->EvalWorldState(t); if ((patchos.obj) && (localData->selfNode)) { iv &= patchos.obj->ObjectValidity(t); Matrix3 patchTM = node->GetObjTMBeforeWSM(t, &iv); Matrix3 baseTM = localData->selfNode->GetObjTMBeforeWSM(t, &iv); PatchObject *patchObj = (PatchObject *) patchos.obj; PatchMesh *patch = &patchObj->patch; BOOL patchValid = TRUE; for (int i =0; i < patch->numPatches; i++) { if (patch->patches[i].type != PATCH_QUAD) { patchValid = FALSE; } } if ((!patchValid) && (ip)) { TSTR name; name.printf(GetString(IDS_ERROR_TRIPATCH)); SetWindowText(GetDlgItem(hWnd,IDC_STATUS),name); } if ((patch->numPatches > 0) && patchValid) { if ( (patch->numPatches != localData->numPatches) || (localData->resample)) { //rebuild the param data BuildParamData(os->obj,localData,patch,patchTM,baseTM); } localData->resample= FALSE; //setup deformer PatchDeformer deformer(localData,patch,baseTM,patchTM); os->obj->Deform(&deformer, TRUE); } } os->obj->UpdateValidity(GEOM_CHAN_NUM,iv); }
/** * This method will be called from the max system when the user * has choosen to export to the OpenSceneGraph format. * This method is the entry point to the exporter plugin. */ int OSGExp::DoExport(const TCHAR *name, ExpInterface *ei, Interface *i, BOOL suppressPrompts, DWORD MAXOptions){ // Only support "one at the time" exporting. if(isExporting){ return FALSE; } isExporting = TRUE; // Grab the interface pointer and save it for later use. _ip = i; // Set export path in options class TCHAR p[300]; TCHAR f[100]; TCHAR e[10]; BMMSplitFilename(name, p, f, e); _options->setExportPath(p); _options->setExportFilename(f); _options->setExportExtension(e); // Get filename to config file. TSTR cfgfilename = _ip->GetDir(APP_PLUGCFG_DIR);; cfgfilename += _T("\\OSGEXP.CFG"); // Load options from config file _options->load(cfgfilename); // Should we only export selected nodes? _onlyExportSelected = (MAXOptions & SCENE_EXPORT_SELECTED) ? TRUE : FALSE; // Show option dialog to user and retrive any possible plugin choices. if(!suppressPrompts) if(!DialogBoxParam(hInstance, MAKEINTRESOURCE(IDD_EXPORTBOX), GetActiveWindow(), OptionsDlgProc, (LPARAM)_options)){ // If user closed or canceled export box then shutdown plugin. isExporting = FALSE; return TRUE; } // Write options to config file. _options->write(cfgfilename); // Create OSG root transform to hold the scene. { osg::ref_ptr<osg::MatrixTransform> rootTransform = new osg::MatrixTransform(); //osg::MatrixTransform* rootTransform = new osg::MatrixTransform(); rootTransform->setName(std::string(_ip->GetRootNode()->GetName())); // Set static datavariance for better performance rootTransform->setDataVariance(osg::Object::STATIC); // Set NodeMask if(_options->getUseDefaultNodeMaskValue()) rootTransform->setNodeMask(_options->getDefaultNodeMaskValue()); osg::Matrix rootMat = getNodeTransform(_ip->GetRootNode(), _ip->GetTime()); rootTransform->setMatrix(rootMat); // Create root stateset for the lights. osg::ref_ptr<osg::StateSet> rootStateSet = new osg::StateSet(); // Turn of lighting if set by the user. if(_options->getTurnOffLighting()) rootStateSet->setMode(GL_LIGHTING,osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF); else rootStateSet->setMode(GL_LIGHTING,osg::StateAttribute::ON); //osg::StateSet* rootStateSet = new osg::StateSet(); rootTransform->setStateSet(rootStateSet.get()); // We will make two progress bars. The first one will show // the exporting of materials, wheras the second one will show // the exporting of nodes. To get the total number of nodes in the // scene graph we will accumulate the total node count while // preprocessing the scenegraph for materials. _nTotalNodeCount = 0; _nCurNode = 0; _nTotalMtlCount = _ip->GetSceneMtls()->Count(); _nCurMtl = 0; // Starting up the material exporting progress bar. _ip->ProgressStart(_T("Exporting materials..."), TRUE, fn, NULL); // Export materials by preprocessing the scenegraph. if(!preProcess(_ip->GetRootNode(), _ip->GetTime())){ // If user cancels we stop progress bar and return. _ip->ProgressEnd(); isExporting = FALSE; return TRUE; } // We're done exporting materials. Finish the progress bar. _ip->ProgressEnd(); // Starting up the node exporting progress bar. _ip->ProgressStart(_T("Exporting scene..."), TRUE, fn, NULL); // Get number of children for the root node in the interface. int numChildren = _ip->GetRootNode()->NumberOfChildren(); // Call our node enumerator. // The nodeEnum function will recurse into itself and // export each object found in the scene. for (int idx=0; idx<numChildren; idx++) { if (_ip->GetCancel() || !nodeEnum(rootTransform.get(), _ip->GetRootNode()->GetChildNode(idx), rootTransform.get())){ // If user cancels we stop progress bar and return _ip->ProgressEnd(); isExporting = FALSE; return TRUE; } } // Finish exporting progress bar _ip->ProgressEnd(); // If optimize scene graph unsigned int optimizeMask = 0; if(_options->getTriStripGeometry()) optimizeMask |= osgUtil::Optimizer::TRISTRIP_GEOMETRY; if(_options->getMergeGeometry()) optimizeMask |= osgUtil::Optimizer::MERGE_GEOMETRY; if(_options->getFlattenStaticTransform()) optimizeMask |= osgUtil::Optimizer::FLATTEN_STATIC_TRANSFORMS; if(_options->getShareDuplicateStates()) optimizeMask |= osgUtil::Optimizer::SHARE_DUPLICATE_STATE; if(_options->getSpatializeGroups()) optimizeMask |= osgUtil::Optimizer::SPATIALIZE_GROUPS; if(optimizeMask){ _ip->ProgressStart(_T("Optimizing scenegraph..."), FALSE, fn, NULL); _ip->ProgressUpdate(0.5f); osgUtil::Optimizer optimizer; optimizer.optimize(rootTransform.get(), optimizeMask); _ip->ProgressEnd(); } // Save file to disk. if(_options->getSaveFile()){ _ip->ProgressStart(_T("Writing file..."), FALSE, fn, NULL); _ip->ProgressUpdate(0.5f); if(_options->getExportExtension().compare(".osg")==0 || _options->getExportExtension().compare(".OSG")==0 || _options->getExportExtension().compare(".ive")==0 || _options->getExportExtension().compare(".IVE")==0 ){ std::string filename(name); // Exclude image data from ive file if this options has been choosen if(!_options->getIncludeImageDataInIveFile()){ osgDB::ReaderWriter::Options* opt = new osgDB::ReaderWriter::Options("noTexturesInIVEFile"); osgDB::Registry::instance()->setOptions(opt); } #if defined(OPENSCENEGRAPH_MAJOR_VERSION) && OPENSCENEGRAPH_MAJOR_VERSION >= 2 && defined(OPENSCENEGRAPH_MINOR_VERSION) && OPENSCENEGRAPH_MINOR_VERSION >= 4 osgDB::ReaderWriter::WriteResult res = osgDB::Registry::instance()->writeNode(*rootTransform, filename, NULL); #else osgDB::ReaderWriter::WriteResult res = osgDB::Registry::instance()->writeNode(*rootTransform, filename); #endif if(res.error() && _options->getShowErrMsg()){ static TCHAR szBuffer[256]; wsprintf(szBuffer,TEXT("Error writing file %s:\n%s"), TEXT(filename.c_str()),res.message()); MessageBox (GetActiveWindow(), szBuffer, TEXT("Warning"), MB_OK | MB_ICONWARNING) ; } if(!_options->getIncludeImageDataInIveFile()){ // Turn readerwriter options off again. osgDB::ReaderWriter::Options* opt = new osgDB::ReaderWriter::Options(); osgDB::Registry::instance()->setOptions(opt); } } else{ if(_options->getShowErrMsg()){ std::string error("Can not find plugin to save file: "); error.append(name); MessageBox (GetActiveWindow(), error.c_str() , TEXT("Warning"), MB_OK | MB_ICONWARNING) ; } } _ip->ProgressEnd(); } // Show quick preview if(_options->getQuickView()){ float fNear = 1.0f; float fFar = 1000.0f; // Get the active viewport and the win32 window within it. // The position and size will be retreive from this. ViewExp* viewExp = _ip->GetActiveViewport(); float fov = viewExp->GetFOV(); HWND hWnd = viewExp->getGW()->getHWnd(); RECT sRect; BOOL ok = GetWindowRect(hWnd, &sRect); int width = 100; int height = 100; int x =100; int y =100; if(ok){ x = sRect.left; y = sRect.top; width = sRect.right - sRect.left; height = sRect.bottom - sRect.top; } // Create previewer window and set size. Previewer previewer; previewer.setWindowSize(x, y, width, height); // The affine TM transforms from world coords to view coords // so we need the inverse of this matrix Matrix3 aTM, camTM, coordSysTM; Point3 viewDir, viewPos, lookAtPos, upVector; INode* camera; float dist = 100; Point3 upperLeft = viewExp->MapScreenToView(IPoint2(0, 0), fFar); Point3 lowerRight = viewExp->MapScreenToView(IPoint2(width, height), fFar); viewExp->GetAffineTM(aTM); coordSysTM = Inverse(aTM); viewDir = coordSysTM.VectorTransform(Point3(0.0f, 0.0f, -1.0f)); viewPos = coordSysTM.GetRow(3); lookAtPos = viewPos + viewDir; upVector.Set(0.0f, 0.0f, 1.0f); switch(viewExp->GetViewType()){ case VIEW_ISO_USER: case VIEW_PERSP_USER: previewer.setProjectionMatrixAsFrustum(lowerRight.x, upperLeft.x, upperLeft.y, lowerRight.y, fFar, -fFar); break; case VIEW_CAMERA: previewer.setProjectionMatrixAsFrustum(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, fFar, -fFar); camera = viewExp->GetViewCamera(); camTM = camera->GetObjTMBeforeWSM(_ip->GetTime()); viewDir = camTM.VectorTransform(Point3(0.0f, 0.0f, -1.0f)); viewPos = camTM.GetRow(3); lookAtPos = viewPos + viewDir; break; case VIEW_LEFT: case VIEW_RIGHT: case VIEW_TOP: case VIEW_BOTTOM: case VIEW_FRONT: case VIEW_BACK: previewer.setProjectionMatrixAsOrtho(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, -fFar, fFar); //cam->setOrtho(upperLeft.x, lowerRight.x, lowerRight.y, upperLeft.y, -fFar, fFar); // Go far away from the viewing point in the negative viewing direction. viewPos = coordSysTM.PointTransform(Point3(0.0f, 0.0f, fFar)); lookAtPos = viewPos + viewDir; // In top view the up vector on the camera is the positive y-axis. if(viewExp->GetViewType() == VIEW_TOP) upVector.Set(0.0f, 1.0f, 0.0f); // In bottom view the up vector on the camera is the negative y-axis. if(viewExp->GetViewType() == VIEW_BOTTOM) upVector.Set(0.0f, -1.0f, 0.0f); break; } // When we are done with the viewport we should release it. _ip->ReleaseViewport(viewExp); // Set scene data. previewer.setSceneData(rootTransform.get()); // set the view - OpenGL look at previewer.setViewMatrixAsLookAt(osg::Vec3( viewPos.x, viewPos.y, viewPos.z), osg::Vec3(lookAtPos.x, lookAtPos.y, lookAtPos.z), osg::Vec3(upVector.x, upVector.y, upVector.z) ); previewer.run(); isExporting = FALSE; return TRUE; } } isExporting = FALSE; return TRUE; }
/** * @brief * Constructor */ PLSceneNode::PLSceneNode(PLSceneContainer *pContainer, IGameNode *pIGameNode, const String &sName, EType nType, const String &sClassName) : m_pContainer(pContainer), m_pIGameNode(pIGameNode), m_sName(sName), m_nType(nType), m_sClassName(sClassName), m_sFlags(""), m_vPos(0.0f, 0.0f, 0.0f), m_vRot(0.0f, 0.0f, 0.0f), m_vScale(1.0f, 1.0f, 1.0f), m_nIsRotationFlipped(-1) { // Check some universal flags INode *pMaxNode = GetMaxNode(); if (pMaxNode) { // If this is not a container... TSTR sString; // Check whether the default PixelLight class is changed if (pMaxNode->GetUserPropString(_T("Class"), sString)) { m_sClassName = sString; // Erase all '"' int i = m_sClassName.IndexOf("\""); while (i >= 0) { m_sClassName.Delete(i, 1); i = m_sClassName.IndexOf("\""); } } // Is this 3ds Max node frozen? if (pMaxNode->IsFrozen()) AddFlag("Frozen"); // Is this 3ds Max node invisible? if (pMaxNode->IsHidden() || !pMaxNode->Renderable()) AddFlag("Invisible"); // Is this 3ds Max node excluded from lighting? INodeGIProperties *pINodeGIProperties = static_cast<INodeGIProperties*>(pMaxNode->GetInterface(NODEGIPROPERTIES_INTERFACE)); if (pINodeGIProperties && pINodeGIProperties->GIGetIsExcluded()) AddFlag("NoLighting"); { // Get the world space bounding box of the scene node. Because this is not 'trival' we're using // the sample code from "3dsMaxSDK.chm" (3ds Max SDK) -> "The Pipeline and the INode TM Methods" // to get it working correctly. ::Object *pMaxObject = pMaxNode->GetObjectRef(); if (pMaxObject) { TimeValue t = 0; Matrix3 mat; // The Object TM // Determine if the object is in world space or object space // so we can get the correct TM. We can check this by getting // the Object TM after the world space modifiers have been // applied. It the matrix returned is the identity matrix the // points of the object have been transformed into world space. if (pMaxNode->GetObjTMAfterWSM(t).IsIdentity()) { // It's in world space, so put it back into object // space. We can do this by computing the inverse // of the matrix returned before any world space // modifiers were applied. mat = Inverse(pMaxNode->GetObjTMBeforeWSM(t)); } else { // It's in object space, get the Object TM mat = pMaxNode->GetObjectTM(t); } // Get the bound box, and affect it by just the scaling portion pMaxObject->GetDeformBBox(t, m_cBoundingBox, &mat); } } // We really need to flip the coordinates to OpenGL style m_cBoundingBox.pmin = PLTools::Convert3dsMaxVectorToOpenGLVector(m_cBoundingBox.pmin); m_cBoundingBox.pmax = PLTools::Convert3dsMaxVectorToOpenGLVector(m_cBoundingBox.pmax); // Validate minimum/maximum - I already had situations with incorrect values causing problems! PLTools::ValidateMinimumMaximum(m_cBoundingBox); } // Get the position, rotation and scale GetPosRotScale(m_vPos, m_vRot, m_vScale); }