Monthly Archives: July 2012

Super Easy to Use 3D Engine (Su3De) – Binary File Format Part 5 – Textures

Peanut Butter Jelly Time

OK…its time for textures.  We have everything we need for a textured 3D model in the .SU3 format except for textures – yes…we will have to add color maps for models that don’t have textures…but all in due time.  Right now…textures.

So, lets say we have a 3D model with geometry:

Ford Flex Model Geometry

Now we want to add a texture map to it.

Ford Flex Model Texture

If all comes out right, we should get this when we render the model:

Ford Flex Model Rendered

A not so long winded texture discussion – hopefully

A texture is simply a bitmap. That’s it.  In the end, just a collection of pixels.  Usually the width and height of the bitmap (almost always) is a power of 2 – like 64×64, 128×128, 512×512, 512×128, etc.   The Ford Flex model texture is 512×512.  As you probably already know, the size of the texture is relatively unimportant – the larger the texture the more detail you can pack into it.  The problem is, the larger the texture, the more work the 3D renderer has to do to draw the model.  There is always a trade off between texture size and speed / performance.

So, what format can a texture be in?  THAT can end up being a complex question. Ultimately, the texture will end up in the format of the actual frame buffer of the graphics controller – but it will undergo a lot of changes along the way – getting sliced, diced, stretched, pulled, pushed, wrapped and mapped onto the triangles that make us the 3D model.  So, does it really matter what format the texture is in to start with? Well…actually yes…it does.  You see, the texture has to be pushed across the “host” memory interface into graphics memory prior to it getting used by the 3D renderer, so…in this case, while a bigger texture map gives you better visual results, smaller textures move across the host interface faster – again…a trade off.

Now…the first and obvious question that comes to mind is this…why can’t I just use PNG and JPG images for my texture map?  Well…you can…and…you can’t.  How’s that for an answer?

When you create your textures using whatever tool you use – PhotoShop, Z-Brush…whatever, you will most likely save out your texture as a pretty common format – like a JPG or PNG. You might even save out as a GIF (why…I don’t know…but you might). Most 3D engines, however, are going to require that you convert from one of these common formats into something it can actually understand and use.  SOME 3D engines will directly perform the JPG / PNG / GIF / blah blah conversion for you…but Su3De won’t.

Never fear, however, the Su3De .SU3 3D model conversion utility, however, will be DELIGHTED to do the texture conversion for you…

Now, the next question is – What will the SU3 model conversion utility convert the texture into?  Tongue in cheek answer – does it matter…do you really care?  Oh…you do? Well here is the answer then.

Bitmaps 101 – kind of

There are many different ways to express pixels in a bitmap.  Too many in fact.  For the purposes of further discussion R = Red component, G = Green component, B = Blue component and A = Alpha component.  As you are almost certainly aware, Alpha is the amount of transparency of the pixel with 0 being completely transparent and “maximum value” (whatever that is based on the bit depth) as fully opaque.

The lowest hanging fruit and simplest of the bitmap formats would be a straight 32-bit ARGB value.  This would mean that there would be 8 bits for each color component as well as the alpha component.  This ostensibly yields 4 billion possible color variations – again…kind of…but not really.  In reality, the number of possible color variations will be dictated by your LCD screen – or display device.  In many cases, the LCD panels are 18-bit yielding only 262,144 possible colors.  Most of the latest LCD panels are 24-bit wide which yields around 16.8 million possible colors. Simply food for thought when picking color depths for textures.

So…lets look at a 32-bit color depth texture:

32 bit frame buffer example

This is an example of “direct color”.  In this example, each pixel requires 4 bytes to represent the color information.  So, for our 16×8 texture, the requirement is 512 bytes.  Seems like a lot of memory for such a small bitmap, doesn’t it?  Now consider a texture that is 512×512 pixels. At 32 bit color, the memory requirement is a whopping 1MB – just for a single texture…like the Ford Flex texture above.  Is there a better way?  I daresay…there is.

What if we used LESS memory for each pixel…I mean do we REALLY need 8 bits for each component?  What if we cut the color depth in half?  Like use 16-bits per pixel instead?  Is this workable?  In fact, yes…it is.  Many / most of the 3D engines we work with will accept wither 32-bit or 16-bit color.  The trade-off?  The number of colors start becoming seriously limited.  Let me explain / show.

With 32-bit color, we have 8 bits for Red, 8 bits for Green and 8-bits for Blue and 8-bits for Alpha.  That means we have 256 SHADES of Red, 256 SHADES of Blue and 256 SHADES of Green to work with.  In many images, there are subtle color gradients that aren’t immediately obvious, because they blend together when we see them.  Our brain does that nifty little trick for us…  When we reduce the color depth, we reduce the number of “SHADES” of a particular color and this can create nasty artifacts called “banding” that makes images look…well…not so hot. Before we continue, lets talk about a couple of other color depth formats that are “common” and ones that we will likely be supporting with Su3De:

  • RGB565 – here we have 5 bits of Red (32 shades), 6 bits of Green (64 shades) and 5 bits of Blue (32 shades).  This results in 16 bits with no alpha channel.  This format is quite common.
  • RGB555 – 5 bits of Red (32 shades), 5 bits of Green (32 shades), 5 bits of Blue (32 shades) and an unused bit -or- the bit can be used for a “global” alpha value – i.e. on or off – interesting effects can be performed with this on the right graphics controller.
  • ARGB4444 – 4 bits of Alpha, 4 bits of Red (16 shades), 4 bits of Green (16 shades) and 4 bits of Blue (16 shades).  This is a format that is actually fairly common as well – for example the Sony Play Station Portable uses this format.

I want to give you an example of these formats with a “worst case” scenario – a fully saturated color (I chose green) gradient.  Here,  you can clearly see the banding in effect.  Then, I will show you a real texture – the Ford Flex – in the various formats.

First – lets look at a 32 / 24 bit example  - ARGB8888 – here we have 256 shades of green.

Green Gradient – ARGB8888

Now – lets take a look at RGB565 – here we have 64 shades of green and we can clearly see some banding. Remember – green has an extra bit for the other primary colors (red and blue) you lose half your colors – down to 32.

Green Gradient – RGB565

Here is RGB555 – 32 shades of green and wow…banding is pretty obvious. This is a common color format in embedded graphics systems.

Green Gradient – RGB555

Here is RGB444 – 16 shades of green…and well…it isn’t pretty.

Green Gradient – RGB444

OK…so this is an example of “worst case” scenarios. A saturated color gradient…but it is instructive to see. Now…I want to digress another moment and talk about 8-bit color.

8-bit “indexed” color and palettes

Wouldn’t it be nifty if we could store bitmaps using only a SINGLE byte?  If we could do this, a 512×512 texture would only be 256KBytes instead of 512KBytes for 16-bit color formats (RGB565/RGB555/RGB444) or 1MByte for 24/32-bit color.

Some graphics controllers DO allow you to use a single byte for a frame buffer / texture / bitmap – whatever.  This is called “indexed color” and it is like a “box of crayons”. Imagine a box of crayons (256 of them in fact) and every crayon is assigned a unique number from 0 to 255. Each crayon can be any color you want it to be – without color depth limitations (OK…it is usually RGB888). In this case, you can create high quality images using a small amount of memory. Take a look at the following example:

8-bit – “Indexed” color

When a value between 0 – 255 is written into the graphics controller’s memory, the graphics controller will go to a table called a “palette” and will index into that table and pull out the RGB value for that particular pixel. Clever, huh?

So…what does a green gradient look like with 256 colors? It looks JUST like its RGB888 counterpart because you can have 256 shades of green in an 8-bit color palette.  For more on indexed / palette color click here.

Back to our regularly scheduled programming

OK, so let’s look at our Ford Flex bitmap in the various color depths.

Here is full 24-bit / 32-bit color:

Ford Flex RGB888

Here it is in 16-bit color – RBB 565 format. You can see some image deterioration, but the image quality is quite acceptable given the fact that you knocked the memory size for the texture in HALF!!!

Ford Flex Texture RGB565

Here is the Ford Flex texture in RGB444 format. Now you can start to see some serious deterioration of image quality.

Ford Flex Texture RGB444

OK…and finally, here is an 8-bit version – which is indexed color / palette driven. You can see again, that this is quite acceptable and given the massive savings in memory and if you have a talented graphics artist around -or you are handy with PhotoShop – then you can probably “tweak” this image to make it work well. The savings in memory for this texture is 75% so it is certainly worth the effort if your graphics controller supports 8-bit textures.

Ford Flex Texture – 8-bit “Indexed” color

Dithering – a neat trick!

A neat trick that we often use when using 16-bit and even 8-bit color is “dithering”. Dithering – according to a nice wikipedia definition – is:

“…an intentionally applied form of noise used to randomize quantization error, preventing large-scale patterns such as color banding in images”

Click here to jump to the full wiki page on dithering.

So…how do you dither a 16-bit or 8-bit image?  One nifty way is a free PhotoShop plugin called “Depth Dither” from Graphest.  Graphest seems to be gone…but the plugin is still floating about in places like cnet and can be downloaded from here. Here is depth dither in action in PhotoShop:

Depth Dither in Action

Here is the result when we apply Depth Dither to the RGB444 Ford Flex texture. Compare this to the RGB444 image above. Pretty amazing…right?

Ford Flex Texture RGB444 dithered

Another way to apply “dither” to 16-bit and 8-bit images is to simply go into PhotoShop -or- Gimp and apply 1% or 2% Gaussian “noise” to the image. We have done this many times and it has yielded good results on SOME images.

Once again…back to our regularly scheduled programming

The purpose of all of these “bunny trails” is to form the basis for the 3D model SU3 conversion tool we are developing.  Specifically, what texture formats will we support and what, if any, conversions will we do on the image data?  These are key questions that must be answered.  So, to short circuit the long explanations, we plan to support the following “uncompressed” image formats in Su3De:

  • ARGB8888 – 8 bits each of alpha, red, green and blue. This format is surprisingly not all that common.  Usually, the red and the blue are swapped and this yields:
  • ABGR8888 – same as ARGB8888 except the red and blue values are swapped – this is a pretty common format.
  • BGRA8888 – yes…sometimes the alpha is the last byte and this changes the ordering of the data.
  • BGR888 – 8 bits of red, green and blue, no alpha – 24-bit format – not so common as a “direct” format – will need conversions on certain graphics controllers.
  • RGB888 – same as BGR888 with red and blue swapped
  • BGR565 – 16-bit format – no alpha.
  • RGB565 – 16-bit format – no alpha.
  • BGRX5551 – 16-bit format – no alpha – upper bit unused
  • BGRA4444 – 16-bit format with alpha – 4 bits of each
  • BGRA5551 – 16-bit format with 1 bit of alpha
  • BGRX8888 – 32-bit format with no alpha – essentially 24-bit color packed into 32-bits – upper 8 bits unused
  • I8 – 8-bit indexed color – palette entry must be supplied

Other formats might be added / supported as needed to round out color depth formats.

The methodology for conversion will be loading a PNG, JPG, GIF, whatever into the SU3 model conversion tool along with the .OBJ file – usually this will be automatically supplied in the corresponding .MTL file, then you will select the color depth for the texture based on a drop down list – and then voila…the SU3 will contain your model and texture in the desired format.

In the NEXT entry, I will show what the chunk header and chunk should look like for a texture and we will also cover COMPRESSED textures.  Texture compression is another very interesting topic and refers to the ability of the graphics controller to handle texture decompression in a hardware unit -rather than being handled by the processor directly – which would really defeat the purpose because then we could just use PNGs or JPGs directly…so something to look forward to.

One more thing

I wanted to give an example of the kind of 3D that Su3De will be doing on an actual embedded device…so here is a reference board with THREE LCDs running a demo that we developed using a basic graphics library with 3D primitives.  This is the Jade MB86R01 graphics controller driving the three displays.  This is EXACTLY the sort of thing Su3De is for.  Enjoy:

Super Easy to Use 3D Engine (Su3De) – Binary File Format Part 4 – Texture Maps

NOTE: There were a few minor errors in a couple of the previous posts.  I just wasn’t consistent in explaining the polygonal mesh with regards to vertices.  I have updated the posts and corrected the errors.  The problems were in the area of describing the vertices per triangle relationship.  So, to recap, there are three vertices per triangle and each vertex is comprised of an x, y and z coordinate.  Each coordinate is comprised of a float which requires four bytes.  So, each triangle of the polygonal mesh requires 36 bytes to describe.

Onward…

OK…finally we get to texture maps in the Su3De binary file format.  Texture maps are fairly straightforward to implement, however, there are lots of details that we have to deal with.  In no real order these details include:

  • Texture map color depth
  • Texture map compression
  • Multi-texturing
  • Texture animation
  • Live video as a texture map
  • Recorded or rendered video as a texture map
  • Texture map dimensions
  • Procedural textures

Something I want to also discuss is “terminology”…it can get muddy sometimes so I want to define the terms the way I want to use them with regards to Su3De.  This might result in a street fight…but that’s OK…I fight dirty.

Street fight over 3D terminology

A “texture map” refers to the coordinates (really just relative offsets into the texture bitmap itself) used to map the texture onto the 3D model’s polygonal mesh.

The term “texture” refers to the actual bitmap bits that are being mapped.

UV coordinates” are the values stored in the texture map (one for each vertex of each triangle and corresponding to each triangle) that are the relative offsets into the texture – normalized as values between 0 and 1.  We use the “U and V” to differentiate from X, Y, and Z that are used for mesh coordinates.

I have written a couple of articles / tech papers that you might find interesting if you are new to 3D and texture mapping.  They can be found here:

// Begin Soapbox

Now…at this point, I am going to climb up on my soap box and say a few things. Some of you have been kind enough to express your opinion with regards to the feature set of Su3De.  I want to remind you of the fact that this is to be a “SUPER EASY TO USE 3D ENGINE”.  This means that, at least in the first versions, there aren’t going to be a lot of powerful fancy features.  Yes, I know many of you are very smart…you have told me so…and that in order to be useful Su3De needs this feature or that.  Let’s get something straight…initially Su3De is being developed to satisfy a specific need that I have for a small feature set in a compact UI environment…nothing more.  I am making it “open source” so that you can freely add the features that you want and hopefully many of these new features will find their way into an official Su3De release in the future.  Yes, I know about shaders.  I know about bump / normal mapping.  I know about object physics, collision detection and reflection mapping and yes I know about open source 3D engines like Irrlicht and Ogre (they are awesome).  I appreciate the comments and PLEASE keep them coming…but bear in mind that the goal is a simple product and the feature set is going to be an extremely small subset of overall 3D functionality to achieve a specific goal.  BTW I REALLY liked the suggestion of converting FreeType text into a 3D object that can be used by Su3De…either statically using some tool -or- doing it at run time “on the fly”.  The “on the fly” method might add weight to Su3De that we don’t have the luxury of, however, this could be a compile option.

//End Soapbox

SU3 File format

Putting the texture map and the textures in the actual 3D model binary format along with the polygonal mesh has been a difficult decision.  Does it really belong there?  What about all the things outlined above – texture animation, live streaming video, recorded rendered video, various formats, etc.?  There are lots of good reasons to make the texture map and textures separate files instead of trying to cram everything into a single binary or a single “entity”.  With all this said, I really want a single file (analogous to a PNG as explained before) that contains the entire 3D object.  The “chunk” architecture of the .SU3 file format easily allows us to reference external files should we choose to implement some “advanced” features at a later time. So the decision is that we will have a texture map and a texture in the SU3 file format along with the mesh data (and other required chunks).

Texture Map

Ok, so remember our friend the cube?  Our cube has six sides and twelve faces because each side is made up of two triangles. This makes for thirty six vertices.  As a reminder the vertices look like this:

[sourcecode language="c"]
#pragma pack(1)
/* structure of floating point xyz coordinates */
typedef struct{
float x;
float y;
float z;
}SU3_VTX3F;

static SU3_VTX3F FlexVerts[] = {
{-10.000000f, 0.000000f, 10.000000f}, //triangle 1
{-10.000000f, 0.000000f, -10.000000f}, //triangle 1
{10.000000f, 0.000000f, -10.000000f}, //triangle 1
{10.000000f, 0.000000f, -10.000000f}, //triangle 2
{10.000000f, 0.000000f, 10.000000f}, //triangle 2
{-10.000000f, 0.000000f, 10.000000f}, //triangle 2
{-10.000000f, 20.000000f, 10.000000f}, //triangle 3
{10.000000f, 20.000000f, 10.000000f}, //triangle 3
{10.000000f, 20.000000f, -10.000000f}, //triangle 3
{10.000000f, 20.000000f, -10.000000f}, //triangle 4
{-10.000000f, 20.000000f, -10.000000f}, //triangle 4
{-10.000000f, 20.000000f, 10.000000f}, //triangle 4
{-10.000000f, 0.000000f, 10.000000f}, //triangle 5
{10.000000f, 0.000000f, 10.000000f}, //triangle 5
{10.000000f, 20.000000f, 10.000000f}, //triangle 5
{10.000000f, 20.000000f, 10.000000f}, //triangle 6
{-10.000000f, 20.000000f, 10.000000f}, //triangle 6
{-10.000000f, 0.000000f, 10.000000f}, //triangle 6
{10.000000f, 0.000000f, 10.000000f}, //triangle 7
{10.000000f, 0.000000f, -10.000000f}, //triangle 7
{10.000000f, 20.000000f, -10.000000f}, //triangle 7
{10.000000f, 20.000000f, -10.000000f}, //triangle 8
{10.000000f, 20.000000f, 10.000000f}, //triangle 8
{10.000000f, 0.000000f, 10.000000f}, //triangle 8
{10.000000f, 0.000000f, -10.000000f}, //triangle 9
{-10.000000f, 0.000000f, -10.000000f}, //triangle 9
{-10.000000f, 20.000000f, -10.000000f}, //triangle 9
{-10.000000f, 20.000000f, -10.000000f}, //triangle 10
{10.000000f, 20.000000f, -10.000000f}, //triangle 10
{10.000000f, 0.000000f, -10.000000f}, //triangle 10
{-10.000000f, 0.000000f, -10.000000f}, //triangle 11
{-10.000000f, 0.000000f, 10.000000f}, //triangle 11
{-10.000000f, 20.000000f, 10.000000f}, //triangle 11
{-10.000000f, 20.000000f, 10.000000f}, //triangle 12
{-10.000000f, 20.000000f, -10.000000f}, //triangle 12
{-10.000000f, 0.000000f, -10.000000f}, //triangle 12
};
#pragma pack()
[/sourcecode]

The wire mesh for the cube looks like the image below:

Cube with 36 vertices

As you can see, and as you know from previous posts, there are three vertices per triangle, so our texture map is also going to have three entries per triangle with each entry representing a UV texture map offset. Below is the code that describes the texture map for the cube.

[sourcecode language="c"]
#pragma pack(1)
static SU3_TEX2F FlexTexMap[36] = {
{0.001200f, 0.665600f}, //triangle 1
{0.001200f, 0.335200f}, //triangle 1
{0.331900f, 0.335200f}, //triangle 1
{0.331900f, 0.335200f}, //triangle 2
{0.331900f, 0.665600f}, //triangle 2
{0.001200f, 0.665600f}, //triangle 2
{0.664100f, 0.333200f}, //triangle 3
{0.333700f, 0.333200f}, //triangle 3
{0.333700f, 0.000800f}, //triangle 3
{0.333700f, 0.000800f}, //triangle 4
{0.664100f, 0.000800f}, //triangle 4
{0.664100f, 0.333200f}, //triangle 4
{0.999300f, 0.333400f}, //triangle 5
{0.665300f, 0.333400f}, //triangle 5
{0.665300f, 0.000800f}, //triangle 5
{0.665300f, 0.000800f}, //triangle 6
{0.999300f, 0.000800f}, //triangle 6
{0.999300f, 0.333400f}, //triangle 6
{1.000000f, 0.666000f}, //triangle 7
{0.665600f, 0.666000f}, //triangle 7
{0.665600f, 0.334200f}, //triangle 7
{0.665600f, 0.334200f}, //triangle 8
{1.000000f, 0.334200f}, //triangle 8
{1.000000f, 0.666000f}, //triangle 8
{0.663000f, 0.665300f}, //triangle 9
{0.334800f, 0.665300f}, //triangle 9
{0.334800f, 0.333800f}, //triangle 9
{0.334800f, 0.333800f}, //triangle 10
{0.663000f, 0.333800f}, //triangle 10
{0.663000f, 0.665300f}, //triangle 10
{0.331900f, 0.332100f}, //triangle 11
{0.000400f, 0.332100f}, //triangle 11
{0.000400f, 0.002000f}, //triangle 11
{0.000400f, 0.002000f}, //triangle 12
{0.331900f, 0.002000f}, //triangle 12
{0.331900f, 0.332100f}, //triangle 12
};
#pragma pack()
[/sourcecode]

The actual texture map for the cube we are describing here looks like the following:


No, there isn’t a problem with the bitmap. The top 1/3 is simply not going to be used. Our cube has six sides, therefore we are going to only use the bottom 2/3rds of our texture map area. The benefit of using a cube is that it is very easy to see each “side”.

With a more complex model, the triangle mapping obviously isn’t so straightforward. Speaking of triangle mapping, here is the same texture with the triangle mapping visually applied. This allows you to clearly see all twelve triangles and how they map to the texture.  OK, so the next thing we have to address is how we are going to add the texture map into the .SU3 binary format.

SU3 – Texture Map Chunk

The texture map chunk is defined simply with the chunk length as the number of bytes required to describe the UV coordinates and the chunk type defined as “MTXM”.  To add the texture map to a SU3 file from part 3′s example, we add the following code:

[sourcecode language="c"]
#define FOURCC_MTXM MAKEFOURCC(‘M’,’T’,’X’,’M’)
#pragma pack(1)
typedef struct{
float u;
float v;
}SU3_TEX2F;
static SU3_TEX2F FlexTexMap[36] = {
{0.001200f, 0.665600f}, //triangle 1
{0.001200f, 0.335200f}, //triangle 1
{0.331900f, 0.335200f}, //triangle 1
{0.331900f, 0.335200f}, //triangle 2
{0.331900f, 0.665600f}, //triangle 2
{0.001200f, 0.665600f}, //triangle 2
{0.664100f, 0.333200f}, //triangle 3
{0.333700f, 0.333200f}, //triangle 3
{0.333700f, 0.000800f}, //triangle 3
{0.333700f, 0.000800f}, //triangle 4
{0.664100f, 0.000800f}, //triangle 4
{0.664100f, 0.333200f}, //triangle 4
{0.999300f, 0.333400f}, //triangle 5
{0.665300f, 0.333400f}, //triangle 5
{0.665300f, 0.000800f}, //triangle 5
{0.665300f, 0.000800f}, //triangle 6
{0.999300f, 0.000800f}, //triangle 6
{0.999300f, 0.333400f}, //triangle 6
{1.000000f, 0.666000f}, //triangle 7
{0.665600f, 0.666000f}, //triangle 7
{0.665600f, 0.334200f}, //triangle 7
{0.665600f, 0.334200f}, //triangle 8
{1.000000f, 0.334200f}, //triangle 8
{1.000000f, 0.666000f}, //triangle 8
{0.663000f, 0.665300f}, //triangle 9
{0.334800f, 0.665300f}, //triangle 9
{0.334800f, 0.333800f}, //triangle 9
{0.334800f, 0.333800f}, //triangle 10
{0.663000f, 0.333800f}, //triangle 10
{0.663000f, 0.665300f}, //triangle 10
{0.331900f, 0.332100f}, //triangle 11
{0.000400f, 0.332100f}, //triangle 11
{0.000400f, 0.002000f}, //triangle 11
{0.000400f, 0.002000f}, //triangle 12
{0.331900f, 0.002000f}, //triangle 12
{0.331900f, 0.332100f}, //triangle 12
};

#pragma pack()

//build and write the texture map chunk
chk.chunkLength = sizeof(FlexTexMap);
chk.chunkType = FOURCC_MTXM;
fwrite(&chk, sizeof(SU3_CHUNK), 1, fp);
fwrite(&FlexTexMap, sizeof(FlexTexMap), 1, fp);
crc = 0×12345678; //bogus placeholder value
fwrite(&crc, sizeof(crc), 1, fp);

[/sourcecode]

After the texture is applied to the polygonal mesh we end up with the following rendered image:

Now…of course we haven’t yet written the actual texture data into the SU3 file, we have only written the texture map.  The texture itself is another complex topic and we will address that in the next post.

Housekeeping

So its time for a little bit of housekeeping for the project.  I have secured the domain name of Su3De.org for the project.  Su3De.org will be the official project page. For the source code we will be using GitHub for this project. The GitHub project site is: https://github.com/ricktewell/Su3De.

There is already quite a bit more code developed for this project then I have written about in the blogs.  It is likely that the GitHub repository will stay far ahead of the blog so if you want to “jump forward” a bit – then GitHub will be the place to go.  For example, the 3D OBJ to SU3 converter is starting to work at this point and I will be adding this source to GitHub soon.

So that’s it for now…see you in Su3De.