The object display API is a retained mode graphics API whose functionality is similar to the cached mesh support found with the DirectX viewport driver. This means that plug-ins describe the data to be displayed in the viewport and update it when needed in a declarative manner. The graphics driver stores an internal representation of this data that it retains from frame to frame and uses for rendering to the viewports. This design allows the graphics driver to optimize the rendering and related processing, and to perform rendering in a separate thread. A retained mode graphics API contrasts with an immediate mode graphics API where the drawing commands are immediately rendered.
The Nitrous display driver provides a compatibility layer for plug-ins developed using the legacy immediate mode GraphicsWindow API. As a result, most plug-ins will not require code changes in order to display in the Nitrous viewport display mode. The cases when plug-in code needs to be changed are described in the following section, Impact on Plug-ins.
The object display API consists of the interface class IObjectDisplay. The Nitrous graphics driver queries plug-ins for this interface in order to get their viewport representation as RenderItemHandles (see IObjectDisplay::GetRenderItems()) and asks them to update it (see IObjectDisplay::UpdateDisplay()). The BaseObject class - which is the base class for all procedural objects and modifiers - exposes the IObjectDisplay interface and provides storage for render item handles (see BaseObject::mRenderItemHandles). It means that even those plug-ins that require changes to their BaseObject::Display() function in order to be displayed correctly in the Nitrous viewport display mode, will only need to override the BaseObject::UpdateDisplay() function.
Most procedural object plug-ins are supported as-is by the Nitrous viewport display driver, except for those that have a lit or textured mesh representation and use Mesh::render() in their implementation of BaseObject::Display(). In these cases, the mesh will display flat shaded and unlit in the Nitrous viewport, but any other part of the plug-ins viewport representation drawn using the GraphicsWindow API will display correctly. If the plug-in explicitly sets the GW_WIREFRAME flag and resets GW_ILLUM or GW_TEXTURE, then the mesh will render correctly in the Nitrous viewport since no lighting or texturing information needs to be translated from the immediate mode graphics driver to the retained mode one.
Following is the ShapeObject display code before the upgrade to support Nitrous viewport graphics mode:
//ShapeObject display code before the upgrade to support Nitrous viewport graphics mode. int ShapeObject::Display(TimeValue t, INode *inode, ViewExp* vpt, int flags) { if (!GetDispRenderMesh()) return 0; // Create a mesh to display and cache it GenerateMesh(t, GENMESH_DEFAULT, NULL); GraphicsWindow *gw = vpt->getGW(); // Call Mesh::render() to display the mesh meshCache.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect():NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls(), ((ReferenceTarget*)this)); return 0; }
Following is the ShapeObject display code after the upgrade to support Nitrous viewport graphics mode:
//After the upgrade to support Nitrous viewport graphics mode. int ShapeObject::Display(TimeValue t, INode *inode, ViewExp* vpt, int flags) { if (MaxGraphics::IsNitrousGraphicsEnabled()) return 0; if(!GetDispRenderMesh()) return 0; // Create a mesh to display and cache it GenerateMesh(t, GENMESH_DEFAULT, NULL); GraphicsWindow *gw = vpt->getGW(); meshCache.render( gw, inode->Mtls(), (flags&USE_DAMAGE_RECT) ? &vpt->GetDammageRect():NULL, COMP_ALL | (inode->Selected()?COMP_OBJSELECTED:0), inode->NumMtls(), ((ReferenceTarget*)this)); return 0; } bool ShapeObject::UpdateDisplay(const MaxSDK::Graphics::MaxContext& maxContext, const MaxSDK::Graphics::UpdateDisplayContext& displayContext) { using namespace MaxSDK::Graphics; if (!GetDispRenderMesh()) { mRenderItemHandles.ClearAllRenderItems(); return true; } // create a mesh to display (leave it in cache) GenerateMesh(displayContext.GetDisplayTime(), GENMESH_DEFAULT, NULL); GenerateMeshRenderItemsContext generateRenderItemsContext; generateRenderItemsContext.GenerateDefaultContext(displayContext); meshCache.GenerateRenderItems(mRenderItemHandles,generateRenderItemsContext); return true; }