MVR portable library

From GDTF Development
Jump to: navigation, search

The VectorworksMVR Lib is a portable library available for Windows, OS X and Linux. To use the VectorworksMVR Lib, you just need to add two header files and two external libraries to your project.

The library allows you to read and write MVR files. This also includes full 3DS support.

These are:

  • VectorworksMVR.framework / VectorworksMVR.dll
  • VWMM.framework / VWMM.dll
  • IMediaRessourceVectorInterface.h
  • VectorworksMVR.h


Writing a file

How to:

	//------------------------------------------------------------------------------------------------
	// Create Pointer to MVR Interface
	IMediaRessourceVectorInterfacePtr mvrFileWrite( IID_MediaRessourceVectorInterface );
	
	//------------------------------------------------------------------------------------------------
	// Open file for writing
	mvrFileWrite->OpenForWrite(FILE_NAME);
	
	
	// Set the library folder for GDTF files. During export the Interface will search in this
	// folder to see if there is a gdtf file that the MVR needs. After that add it to the ZIP file
	mvrFileWrite->AddGdtfFolderLocation(GDTFFOLDER);
	
	//------------------------------------------------------------------------------------------------
	// Open file for writing
	ISceneDataProviderPtr obj;
	mvrFileWrite->CreateDataProviderObject("Test Data", "1", &obj);
	
	obj->AddKeyValue("Key", "Value");
	
	//------------------------------------------------------------------------------------------------
	// Now write positions and symdefs
	IPositionPtr position = nullptr;
	mvrFileWrite->CreatePositionObject(UUID(688696821, 558449194, 2115941252, 1809800703), "My Position", & position);
	
	
	ISymDefPtr symDef1 = nullptr;
	mvrFileWrite->CreateSymDefObject(UUID(122079618, 11832014, 669376348, 947930087), "Symbol Definition for the FocusPoint", & symDef1);
	
	CMyGeometryProvider geometryForTheSymdef;
	symDef1->AddGeometry(STransfromMatrix(), & geometryForTheSymdef);
	
	
	//------------------------------------------------------------------------------------------------
	// Now write
	
	// First create a layer
	ISceneObjPtr layer = nullptr;
	mvrFileWrite->CreateLayerObject(UUID(465143117, 742747285, 1361655924, 1172316535), "My Layer 1", & layer);
	
	
	// Create Focus Point
	ISceneObjPtr focusPoint = nullptr;
	mvrFileWrite->CreateFocusPoint(UUID(1998334672, 457193269, 1786021763, 1463564339), STransfromMatrix(), "My FocusPoint", layer, & focusPoint);
	focusPoint->AddSymbol(STransfromMatrix(), symDef1);
	
	// And place some fixtures in it
	ISceneObjPtr fixture1 = nullptr;
	mvrFileWrite->CreateFixture(UUID(1808353427, 683171502, 518343034, 1766902383), STransfromMatrix(), "My Fixture Name", layer, & fixture1);
	
	fixture1->SetGdtfName("robe@robin mmx spot");
	fixture1->SetGdtfMode("Mode 1 v1.1");
	fixture1->AddAdress(1542, 0);
	fixture1->AddAdress(25, 1);
	fixture1->SetFocusPoint(focusPoint);
	fixture1->SetPosition(position);
	
	// And another fixture
	ISceneObjPtr fixture2 = nullptr;
	mvrFileWrite->CreateFixture(UUID(1136161871, 1699151080, 751939975, 1748783014), STransfromMatrix(), "My Fixture Name", layer, & fixture2);
	
	fixture2->SetGdtfName("robe@robin mmx spot");
	fixture2->SetGdtfMode("My fancy other GDTF DMX Mode");
	fixture2->AddAdress(352, 0);
	fixture2->AddAdress(5684, 1);
	fixture2->SetFocusPoint(focusPoint);
	
	
	//------------------------------------------------------------------------------------------------
	// At the end just call close
	mvrFileWrite->Close();

Reading a file

How to:

	//------------------------------------------------------------------------------------------------
	// Create Pointer to MVR Interface
	IMediaRessourceVectorInterfacePtr mvrFileRead( IID_MediaRessourceVectorInterface );
	
	//------------------------------------------------------------------------------------------------
	// Open file for reading
	mvrFileRead->OpenForRead(FILE_NAME);
	
	//------------------------------------------------------------------------------------------------
	// Traverse SymbolDefs
	size_t  countSymbols = 0;
	mvrFileRead->GetSymDefCount(countSymbols);
	
	for (size_t i = 0; i <countSymbols; i++)
	{
		ISymDefPtr symDef = nullptr;
		mvrFileRead->GetSymDefAt(i, & symDef);
		
		size_t geoCount = 0;
		symDef->GetGeometryCount(geoCount);
		
		for (size_t j = 0; j < geoCount; j++)
		{
			IGeometryReferencePtr geoRef = nullptr;
			symDef->GetGeometryAt(j, & geoRef);

			// This is a little bit tricky, because during the GetGeometry call all the
			// calls from the GeometryRecivers are called.
			// So there are no getters in there, but you have to listen to the calls.
			CMyGeometryReceiver	myReceiver;
		}
	}
	
	
	//------------------------------------------------------------------------------------------------
	// Read Layers
	ISceneObjPtr firstLayer = nullptr;
	mvrFileRead->GetFirstLayer(&firstLayer);
	
	ISceneObjPtr sceneObj = nullptr;
	mvrFileRead->GetFirstChild(firstLayer, &sceneObj);
	
	while (sceneObj)
	{
		ESceneObjType type;
		sceneObj->GetType(type);
		
		if (type == ESceneObjType::Fixture)
		{
			// Do stuff here
		}
		
		//------------------------------------------------------------------------
		// Step to next Obj
		ISceneObjPtr next = nullptr;
		mvrFileRead->GetNextObject(sceneObj, &next);
		sceneObj = next;
	}

Geometry data for MVR

The MVR lib allows to write and read 3DS files. The classes IGeometryProvider and IGeometryReceiver are available for this purpose. All functions in this class are purely virtual. So you have to define them on your own to provide the geometry data for the MVR lib.

The following sections help you to handle these functions.

Adding geometry data to MVR

	//-------------------------------------------------------------------------------------------------------------
	class DYNAMIC_ATTRIBUTE IGeometryProvider
	{
	public:
		virtual	~IGeometryProvider() {}

		class Material
		{
		public:
			virtual ~Material() {}

			virtual void	SetMaterialName(const std::string& name) = 0;

			virtual void	SetTransparencyPercentage(float value) = 0;

			virtual void	SetAmbientColor(const RGBColor& clr) = 0;
			virtual void	SetDiffuseColor(const RGBColor& clr) = 0;
			virtual void	SetSpecularColor(const RGBColor& clr) = 0;

			virtual void	SetTexture(const GeometryTexture& texture) = 0;
			virtual void	SetTextureMask(const GeometryTexture& texture) = 0;
		};

		virtual void GetObjects(std::vector<Sint16>& outObjectIDs, Sint16 parentObjectID=-1) = 0;

		virtual void BeginObject(Sint16 id) = 0;
		virtual void GetVerticesCount(size_t& outCnt) = 0;
		virtual void GetVertex(size_t vertexIndex, double& outX, double& outY, double& outZ, double& outU, double& outV) = 0;
		virtual void GetFacesCount(size_t& outCnt) = 0;
		virtual void GetFace(size_t faceIndex, size_t& outVertexAIndex, size_t& outVertexBIndex, size_t& outVertexCIndex, EGeometryFaceInfo& outInfo) = 0;
		virtual void GetFaceMaterial(size_t faceIndex, IGeometryProvider::Material* material) = 0;
		virtual void EndObject() = 0;
	};

A a c++ code sample that will create a simple box with a red face shown below

class CMyGeometryProvider : public IGeometryProvider
{
public:
	CMyGeometryProvider() {};
	virtual	~CMyGeometryProvider() {}
	
	virtual void GetObjects(std::vector<Sint16>& outObjectIDs, Sint16 parentObjectID)
	{
		// we define only one object at the root level
		if ( parentObjectID == -1 )
			outObjectIDs.push_back( 0 );
	}
	
	virtual void BeginObject(Sint16 id) {}
	virtual void GetVerticesCount(size_t& outCnt) { outCnt = 8; }
	virtual void GetVertex(size_t vertexIndex, double& outX, double& outY, double& outZ, double& outU, double& outV)
	{
		switch ( vertexIndex )
		{
		case 0: outX =  50; outY =  50; outZ = -50; outU = 0; outV = 0; break;
		case 1: outX =  50; outY = -50; outZ = -50; outU = 0; outV = 0; break;
		case 2: outX = -50; outY = -50; outZ = -50; outU = 0; outV = 0; break;
		case 3: outX = -50; outY =  50; outZ = -50; outU = 0; outV = 0; break;
		case 4: outX =  50; outY =  50; outZ =  50; outU = 0; outV = 0; break;
		case 5: outX =  50; outY = -50; outZ =  50; outU = 0; outV = 0; break;
		case 6: outX = -50; outY = -50; outZ =  50; outU = 0; outV = 0; break;
		case 7: outX = -50; outY =  50; outZ =  50; outU = 0; outV = 0; break;
		}
	}
	virtual void GetFacesCount(size_t& outCnt)  { outCnt = 12; }
	virtual void GetFace(size_t faceIndex, size_t& outVertexAIndex, size_t& outVertexBIndex, size_t& outVertexCIndex, EGeometryFaceInfo& outInfo)
	{
		outInfo = EGeometryFaceInfo::LineAllVisible;
		switch ( faceIndex )
		{
		case 0:  outVertexAIndex = 0; outVertexBIndex = 1; outVertexCIndex = 2; break;
		case 1:  outVertexAIndex = 2; outVertexBIndex = 3; outVertexCIndex = 0; break;
		case 2:  outVertexAIndex = 6; outVertexBIndex = 5; outVertexCIndex = 4; break;
		case 3:  outVertexAIndex = 4; outVertexBIndex = 7; outVertexCIndex = 6; break;
		case 4:  outVertexAIndex = 0; outVertexBIndex = 4; outVertexCIndex = 1; break;
		case 5:  outVertexAIndex = 1; outVertexBIndex = 4; outVertexCIndex = 5; break;
		case 6:  outVertexAIndex = 2; outVertexBIndex = 7; outVertexCIndex = 3; break;
		case 7:  outVertexAIndex = 6; outVertexBIndex = 7; outVertexCIndex = 2; break;
		case 8:  outVertexAIndex = 2; outVertexBIndex = 1; outVertexCIndex = 5; break;
		case 9:  outVertexAIndex = 5; outVertexBIndex = 6; outVertexCIndex = 2; break;
		case 10: outVertexAIndex = 4; outVertexBIndex = 0; outVertexCIndex = 3; break;
		case 11: outVertexAIndex = 3; outVertexBIndex = 7; outVertexCIndex = 4; break;
		}
	}

	static size_t TextureFileNameExporter(Uint16 fileID, void* outBuffer, size_t writeBytesCnt)
	{
		size_t result = 0;
		if ( fileID == 1234 )
		{
			memset( outBuffer, 0xFEFC, 10 );	// this is a fake file of 10 bytes
			result = 10;
		}

		return result;
	};

	virtual void GetFaceMaterial(size_t faceIndex, IGeometryProvider::Material* material)
	{
		RGBColor redColor  = { 255, 0, 0 };

		static GeometryTexture	texture;
		texture.fName = "RedMat.jpg";
		texture.fFileCallback_Export	= TextureFileNameExporter;
		texture.fFileCallbackID			= 1234;

		// set the same material to all faces. the library will only create one material as it will combine the materials with the same name
		material->SetMaterialName( "red_mat" );
		material->SetDiffuseColor( redColor );
		material->SetTexture( texture );
	}

	virtual void EndObject()  {}
};

Receiving geometry data from MVR

	//-------------------------------------------------------------------------------------------------------------
	class DYNAMIC_ATTRIBUTE IGeometryReceiver
	{
	public:
		virtual	~IGeometryReceiver() {}

		class Material
		{
		public:
			virtual ~Material() {}

			virtual const std::string&	GetMaterialName() const = 0;

			virtual float					GetTransparencyPercentage() const = 0;

			virtual const RGBColor&			GetAmbientColor() const = 0;
			virtual const RGBColor&			GetDiffuseColor() const = 0;
			virtual const RGBColor&			GetSpecularColor() const = 0;

			virtual bool					HasTexture() const = 0;
			virtual void					GetTexture(GeometryTexture& outTexture) const = 0;
			virtual void					GetTextureMask(GeometryTexture& outTexture) const = 0;
		};

		virtual void BeginObject(Sint16 objectID, Sint16 parentObjectID) = 0;	// parentObjectID = Uint64(-1) when object at root
		virtual void SetVerticesCount(size_t cnt) = 0;
		virtual void SetVertex(size_t vertexIndex, double x, double y, double z, double u, double v) = 0;
		virtual void SetFacesCount(size_t cnt) = 0;
		virtual void SetFace(size_t faceIndex, size_t vertexAIndex, size_t vertexBIndex, size_t vertexCIndex, EGeometryFaceInfo info) = 0;
		virtual void SetFaceMaterial(size_t faceIndex, const IGeometryReceiver::Material* material) = 0;
		virtual void EndObject() = 0;
	};

The following code shows how to pint the data read from the 3DS to the command line.

// This macro ist used to print the entry.
#define _P(x) std::cout << #x <<" = " << x << std::endl

class CMyGeometryReceiver : public IGeometryReceiver
{
public:
	CMyGeometryReceiver() {}
	virtual ~CMyGeometryReceiver() {}

	virtual void BeginObject(Sint16 objectID, Sint16 parentObjectID) { _P(objectID); _P(parentObjectID); }	// parentObjectID = Uint64(-1) when object at root
	virtual void SetVerticesCount(size_t cnt) {_P(cnt);}
	virtual void SetVertex(size_t vertexIndex, double x, double y, double z, double u, double v) { _P(vertexIndex); _P(x);_P(y);_P(z);}
	virtual void SetFacesCount(size_t cnt)	{ _P(cnt); }
	virtual void SetFace(size_t faceIndex, size_t vertexAIndex, size_t vertexBIndex, size_t vertexCIndex, EGeometryFaceInfo info) {_P(faceIndex);_P(vertexAIndex);}
	virtual void SetFaceMaterial(size_t faceIndex, const IGeometryReceiver::Material* material) {_P(faceIndex);}
	virtual void EndObject() {}
};


Textures in MVR

	//-------------------------------------------------------------------------------------------------------------
	enum class EGeometryFaceInfo
	{
		LineABVisible		= 0x04,
		LineBCVisible		= 0x02,
		LineCAVisible		= 0x01,
		LineAllVisible		= 0x07
	};

	//-------------------------------------------------------------------------------------------------------------
	typedef size_t(*TImportBufferCallback)(Uint16 fileID, const void* inBuffer, size_t readBytesCnt);	// return bytes read < readBytesCnt; readBytesCnt is the max bytes that can be read from inBuffer
	typedef size_t(*TExportBufferCallback)(Uint16 fileID, void* outBuffer, size_t writeBytesCnt);		// return bytes written < writeBytesCnt; writeBytesCnt is the max bytes that can be written to outBuffer

	//-------------------------------------------------------------------------------------------------------------
	struct GeometryTexture
	{
		TImportBufferCallback	fFileCallback_Import;	// A callback that will be called when importing/exporting the texture file
		TExportBufferCallback	fFileCallback_Export;	//   providing or requesting the bytes in chunks
		Uint16					fFileCallbackID;		// The ID that will be provided to the callback.
														//   this can be utilized when the same callback will be used for several texture files
		std::string	fName;			// The texture 8.3 file name including extension
		Uint16		fTilingFlags;
		float		fBlurring;
		float		fUOffset;
		float		fUTiling;
		float		fVOffset;
		float		fVTiling;
		float		fRotation;

		GeometryTexture() { fTilingFlags = 0; fBlurring = fUOffset = fUTiling = fVOffset = fVTiling = fRotation = 0; }
	};