bool TurretShape::getWorldNodeTransform(S32 node, MatrixF& mat) { MatrixF nodeMat; if (!getNodeTransform(node, nodeMat)) return false; nodeMat.affineInverse(); mat = nodeMat; return true; }
void AITurretShape::getAimTransform(MatrixF& mat) { if (mDataBlock && mDataBlock->aimNode != -1) { if (getNodeTransform(mDataBlock->aimNode, mat)) { return; } } mat = mObjToWorld; }
void AITurretShape::_renderScanner( ObjectRenderInst *ri, SceneRenderState *state, BaseMatInstance *overrideMat ) { GFXStateBlockDesc desc; desc.setBlend(false, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha); desc.setZReadWrite(false,true); desc.fillMode = GFXFillWireframe; // Render the scan box GFX->getDrawUtil()->drawCube(desc, mTransformedScanBox.getExtents(), mTransformedScanBox.getCenter(), ColorI(255, 0, 0)); // Render a line from the scan node to the max scan distance MatrixF nodeMat; if (getNodeTransform(mDataBlock->scanNode, nodeMat)) { Point3F start; nodeMat.getColumn(3, &start); Point3F end(0.0f, mScanDistance, 0.0f); nodeMat.mulP(end); GFX->getDrawUtil()->drawLine(start, end, ColorI(255, 255, 0)); } }
Exporter::Result Exporter::exportMesh(NiNodeRef &ninode, INode *node, TimeValue t) { ObjectState os = node->EvalWorldState(t); bool local = !mFlattenHierarchy; TriObject *tri = (TriObject *)os.obj->ConvertToType(t, Class_ID(TRIOBJ_CLASS_ID, 0)); if (!tri) return Skip; Mesh *copymesh = NULL; Mesh *mesh = &tri->GetMesh(); Matrix3 mtx(true), rtx(true); if (Exporter::mCollapseTransforms) { mtx = GetNodeLocalTM(node, t); mtx.NoTrans(); Quat q(mtx); q.MakeMatrix(rtx); mesh = copymesh = new Mesh(*mesh); { int n = mesh->getNumVerts(); for ( unsigned int i = 0; i < n; ++i ) { Point3& vert = mesh->getVert(i); vert = mtx * vert; } mesh->checkNormals(TRUE); #if VERSION_3DSMAX > ((5000<<16)+(15<<8)+0) // Version 6+ MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->CheckNormals(); for ( unsigned int i = 0; i < specNorms->GetNumNormals(); ++i ) { Point3& norm = specNorms->Normal(i); norm = (rtx * norm).Normalize(); } } #endif } } // Note that calling setVCDisplayData will clear things like normals so we set this up first vector<Color4> vertColors; if (mVertexColors) { bool hasvc = false; if (mesh->mapSupport(MAP_ALPHA)) { mesh->setVCDisplayData(MAP_ALPHA); int n = mesh->getNumVertCol(); if (n > vertColors.size()) vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); VertColor *vertCol = mesh->vertColArray; if (vertCol) { for (int i=0; i<n; ++i) { VertColor c = vertCol[ i ]; float a = (c.x + c.y + c.z) / 3.0f; vertColors[i].a = a; hasvc |= (a != 1.0f); } } } if (mesh->mapSupport(0)) { mesh->setVCDisplayData(0); VertColor *vertCol = mesh->vertColArray; int n = mesh->getNumVertCol(); if (n > vertColors.size()) vertColors.assign(n, Color4(1.0f, 1.0f, 1.0f, 1.0f)); if (vertCol) { for (int i=0; i<n; ++i) { VertColor col = vertCol[ i ]; vertColors[i] = Color4(col.x, col.y, col.z, vertColors[i].a); hasvc |= (col.x != 1.0f || col.y != 1.0f || col.z != 1.0f); } } } if (!hasvc) vertColors.clear(); } #if VERSION_3DSMAX <= ((5000<<16)+(15<<8)+0) // Version 5 mesh->checkNormals(TRUE); #else MeshNormalSpec *specNorms = mesh->GetSpecifiedNormals (); if (NULL != specNorms) { specNorms->CheckNormals(); if (specNorms->GetNumNormals() == 0) mesh->checkNormals(TRUE); } else { mesh->checkNormals(TRUE); } #endif Result result = Ok; Modifier* geomMorpherMod = GetMorpherModifier(node); bool noSplit = FALSE; // bool noSplit = (NULL != geomMorpherMod); while (1) { FaceGroups grps; if (!splitMesh(node, *mesh, grps, t, vertColors, noSplit)) { result = Error; break; } bool exportStrips = mTriStrips && (Exporter::mNifVersionInt > VER_4_2_2_0); Matrix44 tm = Matrix44::IDENTITY; if ( mExportExtraNodes || (mExportType != NIF_WO_ANIM && isNodeKeyed(node) ) ) { tm = TOMATRIX4(getObjectTransform(node, t, false) * Inverse(getNodeTransform(node, t, false))); } else { Matrix33 rot; Vector3 trans; objectTransform(rot, trans, node, t, local); tm = Matrix44(trans, rot, 1.0f); } tm = TOMATRIX4(Inverse(mtx)) * tm; TSTR basename = node->NodeName(); TSTR format = (!basename.isNull() && grps.size() > 1) ? "%s:%d" : "%s"; int i=1; FaceGroups::iterator grp; for (grp=grps.begin(); grp!=grps.end(); ++grp, ++i) { string name = FormatString(format, basename.data(), i); NiTriBasedGeomRef shape = makeMesh(ninode, getMaterial(node, grp->first), grp->second, exportStrips); if (shape == NULL) { result = Error; break; } if (node->IsHidden()) shape->SetVisibility(false); shape->SetName(name); shape->SetLocalTransform(tm); if (Exporter::mZeroTransforms) { shape->ApplyTransforms(); } makeSkin(shape, node, grp->second, t); if (geomMorpherMod) { vector<Vector3> verts = shape->GetData()->GetVertices(); exportGeomMorpherControl(geomMorpherMod, verts, shape->GetData()->GetVertexIndices(), shape); shape->GetData()->SetConsistencyFlags(CT_VOLATILE); } } break; } if (tri != os.obj) tri->DeleteMe(); if (copymesh) delete copymesh; return result; }
/** * This method will export the argument node and traverse * into its child nodes to export them. */ BOOL OSGExp::nodeEnum(osg::Group* rootTransform, INode* node, osg::Group* parent) { osg::ref_ptr<osg::Group> child = NULL; _nCurNode++; _ip->ProgressUpdate((int)((float)_nCurNode/_nTotalNodeCount*100.0f)); // Stop traversing if the user pressed Cancel. if (_ip->GetCancel()) return TRUE; // If node is hidden and we are not exporting hidden nodes then return. if(node->IsNodeHidden() && !_options->getExportHiddenNodes()){ return TRUE; } // Capture a special group helper if one is returned. // Nodes such as LODs and Switches will have to apply // special flags to their immediate children and thus // cannot be traversed in the normal recursive flow. // osg::Group* specialGroup = NULL; // Only export if hole scene is to be exported or // this node is choosen to be exported. if(!_onlyExportSelected || node->Selected()) { // The ObjectState is a 'thing' that flows down the pipeline containing // all information about the object. By calling EvalWorldState() we tell // max to evaluate the object at the end of the pipeline. // An object may start out as an sphere, but could be modified by an modifier // object, the EvalWorldState will apply all modifiers to the original object // and return the final geometry for the object. ObjectState os = node->EvalWorldState(_ip->GetTime()); // Use temporary variables for cleaner code. Object* obj = os.obj; TimeValue timeValue = _ip->GetTime(); // If this a group node then make a OSG group node and add it to // the parent node and traverse into the children. if(node->IsGroupHead() || obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0)) { // Do not export referenced groups. if(Util::isReferencedByHelperObjects(node, _helperIDs)) return TRUE; osg::MatrixTransform* groupNode = new osg::MatrixTransform(); // Set name of group node. groupNode->setName(std::string(node->GetName())); // Set static datavariance for better performance groupNode->setDataVariance(osg::Object::STATIC); // Are we exporting animations. if(_options->getExportAnimations()){ addAnimation(node, timeValue, groupNode); } // Set NodeMask if(_options->getUseDefaultNodeMaskValue()) groupNode->setNodeMask(_options->getDefaultNodeMaskValue()); groupNode->setMatrix(getNodeTransform(node, timeValue)); parent->addChild(groupNode); parent = groupNode; applyNodeMaskValue(node, timeValue, groupNode); } // If this is not a group node it could be a geomtry object, // a camera, a light, or some other class. Switch the class ID // to carry out a specific export. // Note, it is the obj member of ObjectState which // is the actual object we are exporting. else if(obj != NULL) { Class_ID cid = obj->ClassID(); // We look at the super class ID to determine the type of the object. switch(obj->SuperClassID()) { case GEOMOBJECT_CLASS_ID: if(!Util::isReferencedByHelperObjects(node, _helperIDs)) { child = createGeomObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case CAMERA_CLASS_ID: if(_options->getExportCameras()) { child = createCameraObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case LIGHT_CLASS_ID: if(_options->getExportLights()) { child = createLightObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case SHAPE_CLASS_ID: if(_options->getExportShapes() && !Util::isReferencedByHelperObject(node, OCCLUDER_CLASS_ID)) { child = createShapeObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case HELPER_CLASS_ID: { bool notRefByHelpers = Util::isReferencedByHelperObjects(node, _helperIDs) == NULL; bool exportHelpers = _options->getExportHelpers() == TRUE; if(_options->getExportPointHelpers() && cid == Class_ID(POINTHELP_CLASS_ID,0)) { child = createPointFromHelperObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } if(exportHelpers && notRefByHelpers) { if(cid == OSGGROUP_CLASS_ID) { child = createGroupFromHelper(parent, node, obj, timeValue).get(); } else if(cid == LOD_CLASS_ID) { child = createLODFromHelperObject(parent, node, obj, timeValue).get(); } else if(cid == SWITCH_CLASS_ID) { child = createSwitchFromHelperObject(parent, node, obj, timeValue).get(); } else if(cid == DOFTRANSFORM_CLASS_ID) { child = createDOFFromHelper(parent, node, obj, timeValue).get(); } else { rootTransform->addChild(createHelperObject(rootTransform, node, obj, timeValue).get()); } } } break; default: break; } } } for(int c = 0; c < node->NumberOfChildren(); c++) { if(_ip->GetCancel() || ! nodeEnum(rootTransform, node->GetChildNode(c),child.valid()?child.get():parent)) { // If user cancels export we return false. return FALSE; } } return TRUE; }
/** * 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; }
void Exporter::nodeTransform(Matrix33 &rot, Vector3 &trans, INode *node, TimeValue t, bool local) { Matrix3 tm = getNodeTransform(node, t, local); convertMatrix(rot, tm); trans.Set(tm.GetTrans().x, tm.GetTrans().y, tm.GetTrans().z); }