Geometry Modifier Extensions

This kind of extensions modify geometry just before the render starts. They´re useful to preprocess or refine (displacement, etc...) objects without increasing the size of the scene file. You can even assign another material to the object. This class is defined in mx_geometryextension.h.

class CgeometryModifierExtension : public CbaseExtension
{
public:
    virtual bool initializeForRendering( Cmaxwell* pMaxwell ) = 0;
    virtual bool initializePreview( Cmaxwell* pMaxwell )
    {
        return ( true );
    }

    virtual bool modifyMesh( Cmaxwell::Cobject& originalMesh, Cmaxwell::Cobject& modifiedMesh ) = 0;
    virtual bool usesThisMaterial( const char* materialName ) 
    {
        return false;
    }
    virtual bool getProxyDisplayPoints( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxPoints, dword& nPoints, float*& points )
    {
        return false;
    }
    virtual bool getProxyDisplayLines( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxLines, dword& nPoints, float*& points, dword& nLines, dword*& pointsPerLine )
    {
        return false;
    }
    virtual bool getProxyDisplayFaces( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxFaces, dword& nPoints, float*& points, dword& nFaces, dword*& faces )
    {
        return false;
    }
};

The most important part of the extension functionality resides in modifyMesh , which must be implemented. The rest are optional functions.

One of the other three functions getProxyDisplay* should be implemented if the extension writer wants to draw an approximate proxy of the object in the Studio viewport. For example, the  MaxwellGrass extension uses  getProxyDisplayLines to draw some lines representing grass strands.

The class extension constructor is used mainly to create the extension parameters (look at the example below) and, possibly, allocate data structures needed throughout the life of the extension. These data structures must be freed in the class destructor.  initializeForRendering is called just before rendering starts, and the incoming pMaxwell (always check != NULL ) is useful for accessing the scene while executing modifyMesh.

 

initializeForRendering

virtual bool initializeForRendering( Cmaxwell* pMaxwell ) = 0;

Called at the initial stage before rendering starts. Useful for pre-allocating everything that will be needed during the render. This is especially important for Procedural Geometry extensions.

Arguments

Cmaxwell* pMaxwell : input, pointer to the scene.

Returns

true on success, false otherwise. false aborts the render.

 

initializePreview

virtual bool initializePreview( Cmaxwell* pMaxwell );

Reset all the pointers allocated in getProxyDisplay* and make them ready for reuse.

Arguments

Cmaxwell* pMaxwell : input, pointer to the scene.

Returns

true on success, false otherwise.

 

modifyMesh

virtual bool modifyMesh( Cmaxwell::Cobject& originalMesh, Cmaxwell::Cobject& modifiedMesh ) = 0;

Main function of the extension. It is where the actual work of filling a geometric object is done.

Arguments

Cmaxwell::Cobject& originalMesh : input, reference to the original object. Don't modify!

Cmaxwell::Cobject& modifiedMesh : output, reference to the modified object.

Returns

true on success, otherwise false.

 

usesThisMaterial

virtual bool usesThisMaterial( const char* materialName );

Return true if the object uses the material, otherwise false. Called when checking for unused materials.

Arguments

const char* materialName : name of the material to check.

Returns

true if the material is used by this object, otherwise false.

 

getProxyDisplayPoints

virtual bool getProxyDisplayPoints( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxPoints,
dword& nPoints, float*& points );

Allocates and fills the "points" array with the coordinates of points to be drawn in the Studio viewport. Also sets "nPoints" to the actual number of points filled.

Arguments

Cmaxwell::Cobject& originalMesh : input, reference to the original object.

const dword& percent : input, goes from 0 to 100, indicating the degree of desired precision to draw the proxy.

const dword& maxPoints : input, the maximum number of points allowed.

dword& nPoints : output, the actual number of points allocated. Must be <= maxPoints.

float*& points : output, array with the points, x0y0z0x1y1z1x2y2z2....

Returns

true on success, otherwise false.

 

getProxyDisplayLines

virtual bool getProxyDisplayLines( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxPoints,
const dword& maxLines, dword& nPoints, float*& points, dword& nLines, dword*& pointsPerLine );

Allocates and fills the "points" array and "pointsPerLine" array with with the coordinates of points, and number of points per line to be drawn in the Studio viewport. Also sets "nPoints" to the actual number of points created and nLines to the actual number of lines created.

Arguments

Cmaxwell::Cobject& originalMesh : input, reference to the original object.

const dword& percent : input, goes from 0 to 100, indicating the degree of desired precision to draw the proxy.

const dword& maxPoints : input, the maximum number of points allowed.

const dword& maxLines : input, the maximum number of lines allowed.

dword& nPoints : output, the actual number of points allocated. Must be <= maxPoints.

float*& points : output, array with the points, x0y0z0x1y1z1x2y2z2....

dword& nLines : output, the actual number of lines created. Must be <= maxLines.

dword*& pointsPerLine : output, array with the number of points per line, n0n1n2.... If this array is NULL, then the number of points per line is constant, and is nPoints/nLines.

Returns

true on success, otherwise false.

 

getProxyDisplayFaces

virtual bool getProxyDisplayFaces( Cmaxwell::Cobject& originalMesh, const dword& percent, const dword& maxFaces, dword& nPoints, float*& points, dword& nFaces, dword*& faces );

Allocates and fills the "points" array and "faces" array with with the coordinates of points, and indexes to vertices to be drawn in the Studio viewport. Also sets "nPoints" to the actual number of points created and "nFaces" to the actual number of triangles created.

Arguments

Cmaxwell::Cobject& originalMesh : input, reference to the original object.

const dword& percent : input, goes from 0 to 100, indicating the degree of desired precision to draw the proxy.

const dword& maxPoints : input, the maximum number of points allowed.

const dword& maxFaces : input, the maximum number of faces allowed.

dword& nPoints : output, the actual number of points allocated. Must be <= maxPoints.

float*& points : output, array with the points, x0y0z0x1y1z1x2y2z2....

dword& nFaces : output, the actual number of faces created. Must be <= maxLines.

dword*& faces : output, array with the indices to vertices in the "points" array  v00v01v02v10v11v12v20v21v22....

Returns

true on success, otherwise false.

 

Mesh modifier example
#include <math.h>
#include "extensionmanager.h"
#include "geometryextension.h"
#include "maxwell.h"
#include "maxwellversions.h

class ModifierExamplePlugin : public CgeometryModifierExtension
{
	DECLARE_EXTENSION_METHODS( "modifier_1", ModifierExamplePlugin, 1 )
	Cmaxwell* pMaxwellLocal;

    //Helper function to spit messages to maxwell.
    void printMessage( const char* text, const int code )
    {
        if( pMaxwellLocal != NULL ) 
        {
            char pMessage[ 1024 ];
            sprintf ( pMessage, "[Extension %s] %s", getName(), text );
            pMaxwellLocal->printMessage( pMessage, code );
        }
    }
 
public:
 
	ModifierExamplePlugin()
	{
	}
 
	~ModifierExamplePlugin()
	{
	}

	bool initializeForRendering ( Cmaxwell* pMaxwell )    
	{
        pMaxwellLocal = pMaxwell;
        return true;
    }
	
	//Helper function to spit messages to maxwell.
	void printMessage( const char* text, const int code )
	{
	    if( pMaxwellLocal != NULL )	
		{
        	char pMessage[ 1024 ];
        	sprintf ( pMessage, "[Extension %s] %s", getName(), text );
        	pMaxwellLocal->printMessage( pMessage, code );
    	}
	}	

	bool modifyMesh( Cmaxwell::Cobject& originalMesh, Cmaxwell::Cobject& modifiedMesh )
	{
		//originalMesh is what its name means. Please, don´t modify it. ;-)
		//Gets any mesh and modifies its geometry at will
		char msg[ 256 ];
		CextensionManager* pMan = CextensionManager::instance();
		//Create an Octahedron
		if ( !modifiedMesh.resizeMesh( 6, 0, 8, 1 ) )
		{
		// 6 = new vertices count
		// 0 = new normals count
		// 8 = new faces count
		// 1 = positions per vertex : 1 if no motion blur, 2 if motion blur is wanted
			sprintf( msg, "Error resizing mesh. Aborting" );
			printMessage( msg, 1 );
			return false;//Something went wrong
		}
		//Assign points, faces
		Cpoint point;
		byte sux;
		dword iV = 0;
		point.assign( 0.0, 1.0, 0.0 ); sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices;
		point.assign( 1.0, 0.0, 0.0 ); sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices;
		point.assign( 0.0, 0.0, -1.0 );sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices;
		point.assign( -1.0, 0.0, 0.0 );sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices; 
		point.assign( 0.0, 0.0, 1.0 ); sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices;
		point.assign( 0.0, -1.0, 0.0 );sux = modifiedMesh.setVertex ( iV++, 0, point ); if( !sux ) goto Error_vertices;
		dword iF = 0;
		sux = modifiedMesh.setTriangle ( iF++, 0, 4, 1, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 0, 1, 2, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 0, 2, 3, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 0, 3, 4, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 5, 1, 4, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 5, 2, 1, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 5, 3, 2, 0, 0, 0 ); if( !sux ) goto Error_faces;
		sux = modifiedMesh.setTriangle ( iF++, 5, 4, 3, 0, 0, 0 ); if( !sux ) goto Error_faces;

		return true;//true if successful.
Error_vertices:
		sprintf( msg, "Error setting vertex %d", iV-1 );
		printMessage( msg, 1 );
		return false;
Error_faces:
		sprintf( msg, "Error setting face %d", iF-1 );
		printMessage( msg, 1 );
		return false;
	}
};

extern "C" ALWAYSEXPORT int getSdkVersion()
{
    return MAXWELL_SDK_VERSION;
}

extern "C" ALWAYSEXPORT int StartExtension( CextensionManager& extensionManager )
{
    int i = 0;
    if ( extensionManager.registerGeometryModifierExtension( new ModifierExamplePlugin) ) i++;
    return i;
}