www.xbdev.net xbdev - software development
Saturday April 19, 2014
home | about | contact | Donations

     
 

3D File Formats

Exporting our own vertices and data...

 

 

 

Creating a Milkshape Plug-in (Exporter)

by Ben Kenwright


 

Milkshape is a simple but powerful 3D modelling program which is available for about $25, or you can download it and use it during its trial period.  Its biggest selling point though, is its large number of file formats that it can export to, and of course work with.  From Quake2 (.md2), Quake3(.md3) ,Lightwave, .3ds, .x etc and many many more.  Plus its simple to use, and I found that learning to model game characters in the beginning easier with Milkshape, before moving on to much more powerful packages such as 3d studio max.

 

But less of my selling you this package!  What where going to do, is see about writing a plug-in for Milkshape so you can export the 3d data to a file in a form we want.  We'll only do a basic exporter here, and show you all the data and how to get a hold of it...and export it in a raw format, which we can open in notepad or something and take a looksy at the data.

 

For this tutorial I'll use the free version of Visual C++ compiler, which you can download from the Microsoft website for free.  Of course the principles and how's and why's will still apply to your own custom compiler...so once you understand how it works...you should have no problems.

 

Here is the link for those who want to see where to get the MS Visual C++ Compiler for free:

[http://msdn.microsoft.com/visualc/vctoolkit2003/]

 

 

 

Now we'll do a couple of versions of this code... our first plug-in, won't require any additional libraries or anything like that...you'll be able to build a simple Milkshape plug-in using only the basic of knowledge that I'll give you here....then we'll move on to mention the Milkshape SDK and some of the useful library functions you can use.

 

First, let me tell you what the plug-in is...and where you put it to use it with Milkshape.  What we build is a 'dll'...not a exe okay...and we put this dll in the Milkshape directory, where-ever that might be.  On my computer its at: 'C:\Program Files\MilkShape 3D\'.  So if you take a looksy in that folder, you'll see there are lots of dll's in there... here is a list of some:

 

ms3DSExporter.dll
ms3DSImporter.dll
ms3dtExporter.dll
msABCExporter.dll
msABCImporter.dll
msAlignment.dll
msASCIIExporter.dll
msASCIIImporter.dll

...etc etc etc

 

There's a lot of dll's in there...but the majority of them, as you'll notice start with 'ms'.  Which is one of the things you have to know...as our plug-in dll has to start with 'ms' also for it to work with Milkshape...the rest of the name doesn't really matter...only that the first two characters are m and s.

 

Lets create a simple piece of code, and compile it to create a dll to get us going:

 

Basic dll Code (Download Source Code) - testdll.cpp

// Simple test program to test creation of a dll using the command prompt

// and visual studio

 

// auth: bkenwright@xbdev.net

 

// HOW TO COMPILE:

// c:> cl /LD testdll.cpp

 

extern "C" __declspec(dllexport) void __cdecl test();

 

void __cdecl test ()

{

 

}

 

 

If you compile the above code, you should get a nice dll :)  Just to get us set-up and ready to go.

 

WARNING!
When you compile the dll, we will be using the '__stdcall' calling convention, due to use working with classes.  Now we need to force our compiler/linker to name our exported dll functions to our name that we need.  As by default, if we use '__stdcall' it will decorate our function names like this:  "_MyFunction@8'.  This is the standard way without a def file.

The if we include a 'def' file...which is basically a txt file, and we pass the name of it as a parameter when we compile, then we can force the exported function names to be what we want.  For example this would be an 'def' file for our above example code (testdll.def) :

 

LIBRARY "testdll"

 

EXPORTS

   test

 

So we could change or command line to:  cl /LD testdll.cpp  testdll.def

 

 

We'll call our first exporter 'msRawA'...and so we'll create the files with its similar nameing 'msRawA.cpp' and 'msRawA.def'  These are the only two files we need to create our exporter...simple eh?  Well of course you've not seen inside them yet..hehe...but there not bad.  The Milkshape workings are pretty straight forward and easy to understand once you've seen them.

The only function that we need to export is called 'CreatePlugIn()'  Thats it!  No other functions...so our .def file is pretty straight forward and looks like this:

 

msRawA.def

LIBRARY "msRawA"

 

EXPORTS

                 CreatePlugIn

 

 

Here is the code for a very very simple exporter...all it does when you run it, is write a file in the C directory which contains how many mesh's you've got open in 3D milkshape.  Its the start of our journey.

 

code: msRawA.cpp (Download)

 

// Milkshape Exporter

// bkenwright@xbdev.net

 

// cl /LD msRawA.cpp msRawA.def

 

// Few notes:

// The first two letters of our exporter dll, must be 'ms'...so for example you can have

// msMyCool.dll, myRawXBDEV.dll etc.

// You usually need a 'def' (definition) file for visual studio, as it uses __stdcall, so

// it decorates the exported function name...by using a def file, you stop this!

 

 

#include <string.h> // Needed for strcpy(..)

#include <stdio.h>  // for fopen and fprint etc

 

 

// msRawXBDEV.def

/*

LIBRARY "msRawA"

 

EXPORTS

   CreatePlugIn

*/

 

 

// ----------------------------------------------------------------------------------

// A simplified version of the msModel structure that milkshape uses - the

// void* pointers usually point to the sub structures that contain the data.

 

/* msModel */

typedef struct msModel

{

    int         nNumMeshes;

    int         nNumAllocedMeshes;

    void*       pMeshes;

 

    int         nNumMaterials;

    void*       pMaterials;

 

    int         nNumBones;

    int         nNumAllocedBones;

    void*       pBones;

 

    int         nFrame;

    int         nTotalFrames;

 

    float*      Position;

    float*      Rotation;

} msModel;

 

 

// ----------------------------------------------------------------------------------

 

class MyPlugin

{

public:

   MyPlugin(){  strcpy(szTitle, "www.xbdev.net - Custom Raw Exporter"); }

   virtual ~MyPlugin() { }

 

   // Do we want an exporter or a tool?..hmmm, well we decide that here

   virtual int GetType()

   {

      return 2; // What type of plug-in this is '2' indicates an export plugin

   }

 

   virtual const char *GetTitle(){ return szTitle; }

   virtual int Execute(msModel *);

 

private:

   char szTitle[64];

};

 

// Our work horse file

int MyPlugin::Execute( msModel * pModel )

{

   if (!pModel) return -1; // Tiny bit of error checking :)

     

    // export our data

    // Default File Location is C drive, with a default name of "raw.txt"

    char szFile[] = "C:\\raw.txt";

    FILE *file = fopen (szFile, "wt");

    if (!file)

        return -1;

 

    fprintf(file, "nNumMeshes %d\n", pModel->nNumMeshes);

 

    fclose(file);

 

    // We should destroy pModel here as well, but we won't worry about that yet

    return 0;

}

 

 

 

MyPlugin *CreatePlugIn()

{

   return new MyPlugin;

}

 

 

The code is relatively simple but it shows the main functions that are needed to construct an exporter:

 

CreatePlugin()

MyPlugin() constructor

virtual MyPlugin() descructor

virtual GetType()

virtual GetTitle()

virtual Execute()

 

I've added the word virtual to some of the functions, as they must be declared virtual - this is due to the fact that we usually have a class defining these functions...soft of a defintion class only containing these and you would inherite the class from this one and implement your own code.

Lets look at what each of these functions does.  The CreatePlugin() class basically creates an instance of our class and returns a pointer of it to Milkshape.  When an instance of the class is created, the constructor is called...and inside our constructor we've simply copied a string into a char buffer.  This char buffer, called szTitle contains the name that will be displayed in the drop down menu in Milkshape exporter options.  Then GetType() is used to determine what type of plug-in this is - as we are only interested in a file exporter we return 2...which is the number for a exporter...simple as that. Next GetTitle() gets called when milkshape wants to know the title of our exporter - here we just return a pointer to our string, which containes "www.xbdev.net - Custom Raw Exporter".

Finally, the 'Execute()' function is where all the hard work code would go.  This is called when you finally click on you exporter in the drop down menu in Milkshape - it gets passed a pointer to a 'msModel' structure, which is basically a structure of pointers and data values...representing all our 3D data, which we can pick and choose from and export as we need.

 

 

So compile this puppy, and copy the dll to your milkshape folder....then run milkshape.  If it crashes, something went wrong..hehe...but it worked for me, so it should have worked for you as well.

 

 

Well we know its working...and if you click on the option...nothing much will happen...no pops...or anything.  But it will create an output for us :)  If you go to your C drive, you'll find a folder call raw.txt.  You can open it with notepad and view the contents.  I doodles a couple of spheres, so I get:

 

nNumMeshes 2
 

Which shows I had two meshes.  Its not much...but we are given a pointer to the data, which gives us the ability to write a full custom exporter - either to export to a pre-done file format such as Quake(.md2) or Directx(.x)...or even POG (.pog)...hehe...which is our own custom format...I came up with the name pog..hehe...you can do your own exporter and call it what you want.  Many gaming companies and people who produce demo's these days, write there own custom formats and exporters, creating 3d data files that meet there needs.

 

 

Add more power!...MORE POWER!!!

Well I didn't want to give you to much code in one go...as the previous code doens't really give us much power does it...as we don't know the full extents of our msModel...we need to know how its layed out.  And I didn't want to bring in class inheritence, incase it made things complicated.  So now we know which functions are important and how it ticks...so we can add in the extra code which will make our code export the actual model data...OOooo...this is exciting...well I think it is :)

 

 

Exporter code: Download Source (msRawB.cpp)
 

// Milkshape Exporter

// bkenwright@xbdev.net

 

// cl /LD msRawB.cpp msRawB.def

 

// Few notes:

// The first two letters of our exporter dll, must be 'ms'...so for example

// you can have msMyCool.dll, myRawXBDEV.dll etc.

// You usually need a 'def' (definition) file for visual studio, as it uses

// __stdcall, so it decorates the exported function name...by using

// a def file, you stop this!

 

#include <string.h> // Needed for strcpy(..)

#include <stdio.h>  // for fopen and fprint etc

 

// msRawB.def

/*

LIBRARY "msRawB"

 

EXPORTS

   CreatePlugIn

*/

//--------------------------------------------------------------------------

 

/**********************************************************************

 *

 * Constants

 *

 **********************************************************************/

 

#define MS_MAX_NAME             32

#define MS_MAX_PATH             256

 

/**********************************************************************

 *

 * Types

 *

 **********************************************************************/

#pragma pack(1)

 

#ifndef byte

typedef unsigned char byte;

#endif /* byte */

 

#ifndef word

typedef unsigned short word;

#endif /* word */

 

typedef float   msVec4[4];

typedef float   msVec3[3];

typedef float   msVec2[2];

 

/* msFlag */

typedef enum {

    eSelected = 1, eSelected2 = 2, eHidden = 4, eDirty = 8,

            eAveraged = 16, eUnused = 32

} msFlag;

 

/* msVertex */

typedef struct msVertex

{

    byte        nFlags;

    msVec3      Vertex;

    float       u, v;

    char        nBoneIndex;

} msVertex;

 

/* msTriangle */

typedef struct

{

    word        nFlags;

    word        nVertexIndices[3];

    word        nNormalIndices[3];

    msVec3      Normal;

    byte        nSmoothingGroup;

} msTriangle;

 

/* msMesh */

typedef struct msMesh

{

    byte        nFlags;

    char        szName[MS_MAX_NAME];

    char        nMaterialIndex;

   

    word        nNumVertices;

    word        nNumAllocedVertices;

    msVertex*   pVertices;

 

    word        nNumNormals;

    word        nNumAllocedNormals;

    msVec3*     pNormals;

 

    word        nNumTriangles;

    word        nNumAllocedTriangles;

    msTriangle* pTriangles;

} msMesh;

 

/* msMaterial */

typedef struct msMaterial

{

    int         nFlags;

    char        szName[MS_MAX_NAME];

    msVec4      Ambient;

    msVec4      Diffuse;

    msVec4      Specular;

    msVec4      Emissive;

    float       fShininess;

    float       fTransparency;

    char        szDiffuseTexture[MS_MAX_PATH];

    char        szAlphaTexture[MS_MAX_PATH];

    int         nName;

} msMaterial;

 

/* msPositionKey */

typedef struct msPositionKey

{

    float       fTime;

    msVec3      Position;

} msPositionKey;

 

/* msRotationKey */

typedef struct msRotationKey

{

    float   fTime;

    msVec3  Rotation;

} msRotationKey;

 

/* msBone */

typedef struct msBone

{

    int             nFlags;

    char            szName[MS_MAX_NAME];

    char            szParentName[MS_MAX_NAME];

    msVec3          Position;

    msVec3          Rotation;

 

    int             nNumPositionKeys;

    int             nNumAllocedPositionKeys;

    msPositionKey*  pPositionKeys;

 

    int             nNumRotationKeys;

    int             nNumAllocedRotationKeys;

    msRotationKey*  pRotationKeys;

} msBone;

 

/* msModel */

typedef struct msModel

{

    int         nNumMeshes;

    int         nNumAllocedMeshes;

    msMesh*     pMeshes;

 

    int         nNumMaterials;

    int         nNumAllocedMaterials;

    msMaterial* pMaterials;

 

    int         nNumBones;

    int         nNumAllocedBones;

    msBone*     pBones;

 

    int         nFrame;

    int         nTotalFrames;

 

    msVec3      Position;

    msVec3      Rotation;

} msModel;

 

#pragma pack()

 

// ----------------------------------------------------------------------------

 

class cMsPlugIn

{

public:

    enum

    {

      eTypeImport  = 1,

      eTypeExport  = 2,

      eTypeTool    = 3,

      eTypeEdit    = 4,

      eTypeVertex  = 5,

      eTypeFace    = 6,

      eTypeAnimate = 7

    };

 

public:

    cMsPlugIn () {};

    virtual ~cMsPlugIn () {};

 

public:

    virtual int             GetType () = 0;

    virtual const char *    GetTitle () = 0;

    virtual int             Execute (msModel* pModel) = 0;

};

 

// -----------------------------------------------------------------------

 

class MyPlugin : public cMsPlugIn

{

public:

   MyPlugin()

   {

      strcpy(szTitle, "www.xbdev.net - Custom Raw Exporter");

   }

 

   virtual ~MyPlugin() { }

 

   // Do we want an exporter or a tool?..hmmm, well we decide that here

   int GetType()

   {

      return cMsPlugIn::eTypeExport;

   }

 

   const char *GetTitle()

   {

      return szTitle;

   }

 

   int Execute(msModel *);

 

private:

   char szTitle[64];

};

 

 

int MyPlugin::Execute( msModel * pModel )

{

   if (!pModel) return -1;

 

    // Export our data from here on

 

    // Default File Location is C drive, with a default name of "raw.txt"

    char szFile[] = "C:\\raw.txt";

    FILE *file = fopen (szFile, "wt");

    if (!file)

        return -1;

 

    int nNumMeshes = pModel->nNumMeshes;

    fprintf(file, "nNumMeshes %d\n", nNumMeshes);

 

    msMesh * pMeshes = pModel->pMeshes;

    for(int i=0; i<nNumMeshes; i++)

    {

       fprintf(file, "Mesh: %d\n", i);

 

       fprintf(file, "szName: %s\n", pMeshes[i].szName);

       fprintf(file, "nNumVertices: %d\n",pMeshes[i].nNumVertices);

 

       for(int j=0; j< pMeshes[i].nNumVertices; j++)

       {

          msVertex * pVertices = pMeshes[i].pVertices;

          fprintf(file, "x:%f, y:%f, z:%f\n",

               pVertices->Vertex[0],

               pVertices->Vertex[1],

               pVertices->Vertex[2] );

         

       }//End inner for loop

    }//End outer for loop

   

    fclose(file);

 

    // We should destroy pModel here as well

    return 0;

}

 

 

cMsPlugIn *CreatePlugIn()

{

   return new MyPlugin;

}

 

 

 

The above code has added the full definition of the various Milkshape msModel structure - so you can now get access to all the model data and export it to a file.  For example, I created a couple of cubes in Milkshape and used our exporter, and below is wha the output looks like:

 

Output File: raw.txt

nNumMeshes 2

Mesh: 0

szName: Box01

nNumVertices: 20

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

x:-3.750000, y:11.250000, z:8.000000

Mesh: 1

szName: Box02

nNumVertices: 20

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

x:-2.875000, y:-12.000000, z:-14.250000

 

 

What we have done, is export all the vertex data, and write it to file.  The code that does this is in the 'Execute(..)' method of our class.  We've also inherited from a model class, which defines the functions for us.  This is moving towards the Milkshape SDK, which has a class defined liket his and also the model structures....you then only need to include the header file and your away.  Write a simple exporter has never been easier.

 

ERRORS
I've not mentioned it yet.  But the packing of the structures has to be 1!  If you look carefully at our definitions above, I've used '#pragma pack(1)' at the start of our structures and '#pragma pack()' at the end.  Which tells visual studio to pack our data to an alignement of 1 byte...so in essence there'll be no padding bytes, which is what we want.

I found though, in the SDK that it doesn't do this, so when I was trying to export data, it would produce invalid values....only by adding these couple of lines did it fix it!  So now you know :)

 

 

Exporter using Milkshape SDK

You can also download the Milkshape SDK, which is just a couple of .h files and a .lib file, which you can include in your code...saves you re-inventing the wheel as they say.  The .lib defines some pre-written functions which you can use to access the various data types, instead of searching through the pointers for meshes with certain names etc...you can call one of the library functions to search for you.

 

Here is a simple raw exporter that I wrote and use for various demo's when I just need some basic test data:

 

 

Code: msRawXBDEV.cpp (Download)

 

// Milkshape Exporter

// bkenwright@xbdev.net

 

// cl /LD msRawXBDEV.cpp msRawXBDEV.def

 

// msRawXBDEV.def

/*

LIBRARY "msRawXBDEV"

 

EXPORTS

   CreatePlugIn

*/

 

 

// Few notes:

// The first two letters of our exporter dll, must be 'ms'...so for example you can have

// msMyCool.dll, myRawXBDEV.dll etc.

// You usually need a 'def' (definition) file for visual studio, as it uses __stdcall, so

// it decorates the exported function name...by using a def file, you stop this!

 

 

#include "msLib\\msPlugIn.h"

#include <string.h> // Needed for strcpy(..)

#include <stdio.h>  // for fopen and fprint etc

 

// Well I get lazy, having to write my own code to determine where a certain model

// is, or to be able to dump all the data...so there is a small library which

// we can use to do it...which is part of the milkshape sdk...we don't need it, but

// it doesn't harm to know how to use it :)

#include "msLib\\msLib.h"

#pragma comment(lib, "msLib\\lib\\msModelLib.lib")

 

// ----------------------------------------------------------------------------------------------

 

class MyPlugin : public cMsPlugIn

{

public:

   MyPlugin()

   {

      strcpy(szTitle, "www.xbdev.net - Custom Raw Exporter");

   }

 

   virtual ~MyPlugin() { }

 

   // Do we want an exporter or a tool?..hmmm, well we decide that here

   int GetType()

   {

      //return cMsPlugIn::eTypeTool;

      return cMsPlugIn::eTypeExport;

   }

 

   const char *GetTitle()

   {

      return szTitle;

   }

 

   int Execute(msModel *);

 

private:

   char szTitle[64];

};

 

// Very naughty problem that I encountered!  The library's for the default

// milkshape dotn' account for packing alignment :(

#pragma pack(1)

typedef struct msVertexX

{

    byte        nFlags;

    msVec3      Vertex;

    float       u, v;

    char        nBoneIndex;

} msVertexX;

#pragma pack()

 

int MyPlugin::Execute( msModel * pModel )

{

   if (!pModel)

      return -1;

   if (msModel_GetMeshCount (pModel) == 0)

      return 0;

 

    // Export our data

       // Default File Location is C drive, with a default name of "raw.txt"

    char szFile[] = "C:\\raw.txt";

    FILE *file = fopen (szFile, "wt+");

 

    if (!file)

        return -1;

 

    int i, j;

   

    for (i = 0; i < msModel_GetMeshCount (pModel); i++)

    {

        msMesh *pMesh = msModel_GetMeshAt (pModel, i);

 

        for (j = 0; j < msMesh_GetTriangleCount (pMesh); j++)

        {

            msTriangle *pTriangle = msMesh_GetTriangleAt (pMesh, j);

            word nIndices[3];

            msTriangle_GetVertexIndices (pTriangle, nIndices);

           

            // We should really check if each material has a material assigned to it

            unsigned int colour = 0xffffffff;

            

            // Get the colour for our triangle:

            if( msModel_GetMaterialCount(pModel) > 0 )

            {

                        int indx = msMesh_GetMaterialIndex (pMesh);

                        msMaterial* pMat = msModel_GetMaterialAt(pModel, indx);

                        

                        //typedef float   msVec4[4];

                       

                                                int amber = (int)(255 * pMat->Diffuse[3]);

                                                int red   = (int)(255 * pMat->Diffuse[0]);

                                                int green = (int)(255 * pMat->Diffuse[1]);

                                                int blue  = (int)(255 * pMat->Diffuse[2]);

                       

                        // 0xAARRGGBB

                        colour =     amber << 24 |

                                     red   << 16 |

                                     green << 8  |

                                     blue;

            }

 

            msVertexX *pVertex;

            pVertex = (msVertexX*)msMesh_GetVertexAt (pMesh, nIndices[0]);

            fprintf (file, "%f %f %f      ", pVertex->Vertex[0], pVertex->Vertex[1], pVertex->Vertex[2]);

            pVertex = (msVertexX*)msMesh_GetVertexAt (pMesh, nIndices[1]);

            fprintf (file, "%f %f %f      ", pVertex->Vertex[0], pVertex->Vertex[1], pVertex->Vertex[2]);

            pVertex = (msVertexX*)msMesh_GetVertexAt (pMesh, nIndices[2]);

            fprintf (file, "%f %f %f      ", pVertex->Vertex[0], pVertex->Vertex[1], pVertex->Vertex[2]);

            fprintf (file, "0x%.8X\n", colour);

        }

    }

    fclose (file);

 

    // dont' forget to destroy the model

    msModel_Destroy (pModel);

 

    return 0;

}

 

 

cMsPlugIn *CreatePlugIn()

{

   return new MyPlugin;

}

  

 

 

Notice how much simpler it is, when we use the pre-made headers....but of course, you now know how to write an exporter without the Milkshape SDK!...and of course you could write better library's for yourself and of course build up your own extras that you can just use to develop your plug-ins for Milkshape :)

 

Here is what my custom 'rawXBDEV' file output looks like for a simple cube:

 

File Output: raw.txt

-3.500000 10.750000 -3.750000 -3.500000 3.750000 -3.750000 3.500000 10.750000 -3.750000 0xFFFFFFFF

-3.500000 3.750000 -3.750000 3.500000 3.750000 -3.750000 3.500000 10.750000 -3.750000 0xFFFFFFFF

3.500000 10.750000 -3.750000 3.500000 3.750000 -3.750000 3.500000 10.750000 -10.750000 0xFFFFFFFF

3.500000 3.750000 -3.750000 3.500000 3.750000 -10.750000 3.500000 10.750000 -10.750000 0xFFFFFFFF

3.500000 10.750000 -10.750000 3.500000 3.750000 -10.750000 -3.500000 10.750000 -10.750000 0xFFFFFFFF

3.500000 3.750000 -10.750000 -3.500000 3.750000 -10.750000 -3.500000 10.750000 -10.750000 0xFFFFFFFF

-3.500000 10.750000 -10.750000 -3.500000 3.750000 -10.750000 -3.500000 10.750000 -3.750000 0xFFFFFFFF

-3.500000 3.750000 -10.750000 -3.500000 3.750000 -3.750000 -3.500000 10.750000 -3.750000 0xFFFFFFFF

-3.500000 10.750000 -10.750000 -3.500000 10.750000 -3.750000 3.500000 10.750000 -10.750000 0xFFFFFFFF

-3.500000 10.750000 -3.750000 3.500000 10.750000 -3.750000 3.500000 10.750000 -10.750000 0xFFFFFFFF

-3.500000 3.750000 -3.750000 -3.500000 3.750000 -10.750000 3.500000 3.750000 -3.750000 0xFFFFFFFF

-3.500000 3.750000 -10.750000 3.500000 3.750000 -10.750000 3.500000 3.750000 -3.750000 0xFFFFFFFF

 

Where have <triangleA> <triangleB> <triangleC> <Colour> for the data on each line....where each triangle is made up of 3 points.  Its probably not to easy to see, due to the html layout of this page...but there are spaces between the data....so don't go thinking its long lines of numbers.  Its not the most efficient way to save data to file, where we are saving each triangle and not a common list of vertices and references to them...but hey, you can now write your own cool exporter for you demos :)

 

I've gave you the power of 'how to' now....with this knowledge you can go forward and develop more plugs.

 

A note on writing an importer - with an importer, you are passed the pModel, and you are to add data to this model...so your 'Execute(..)' function still does all the work...but this time its loading data and decoding it instead of the other way round.

 

Improving your exporter or possibly any of your plug-ins, I would recommend adding a pop up menu or something like most of the other plug-ins....a simple dialog box with options...makes it more professional - and you can add further options to your output depending on what was selected in the pop up dialog box :).

 

 

Well until next time coders.

 

Happy Coding

 

 

 

 

 

 
 Visitor: 8534626  { 209.237.238.175 } Copyright 2002-2013 xbdev.net - All rights reserved.
Designated tutorial and software are the property of their respective owners.