MDJ File Format

For general discussion of Project Volucris

Moderators: Joe M., Karl G.

MDJ File Format

Postby Karl G. » Mon Apr 02, 2007 1:25 pm

Anyone interested in a description of Xenimus's MDJ file format along with some source code to load MDJ models?

Karl
User avatar
Karl G.
Lesser Spirit
 
Posts: 2453
Joined: Sat Mar 04, 2006 10:26 am

Postby Xodus » Mon Apr 02, 2007 3:38 pm

I'm interested if I can look at it and get a basis for how basic models/textures are loaded...if that's what you're asking. :)
Xodus
Villager
Villager
 
Posts: 6
Joined: Thu Dec 21, 2006 11:26 pm

Postby Karl G. » Mon Apr 02, 2007 4:22 pm

Yep that's exactly what I mean. Here's some of the information, I'll be writing a PDF on this sometime soon. These are just my random notes, in case you feel like doing some scouting yourself. I've also added the three main code files to the end of this post--they're pretty much a hacked together mess right now, but they get the job done. I have a much cleaner/more optimized version that I use for PV. Also, this code can only load non-animated meshes.

This is the format of the chicken.mdj file:
Code: Select all
header[52] = { 50, 0, [[0, 17, 26, 35, 44, 49, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54,]] 53, }

// the first two entires are actually the file-type indicator!!!
// The header component specified inside [[...]] specifies one more than the maximum vertex index used by the subset of its index.  there are ***50*** maximum subsets
// For example, the maximum vertex of subset 0 is -1 (it doesn't exist) 
// the maximum vertex of subset 1 is 16, 2 is 25, 3 is 34, 4 is 43, 5 is 48, 6 is 54
// note that the first subset includes the 128-tagged quads...
// the last number specifies the number of vertices - 1 (or the maximum vertex index...)

Reading 54 vertices...success!
Reading 48 quads...success!


vertices[54] = {
   [0]: { -32.34,   183.00,   19.14,   0x4B48C8C8,   0x0 }
   [1]: { 49.09,   193.00,   52.57,   0x4B48C8C8,   0x0 }
   [2]: { 51.98,   193.00,   -55.40,   0x4B48C8C8,   0x0 }
   [3]: { -33.65,   183.00,   -19.89,   0x4B48C8C8,   0x0 }
   [4]: { 170.42,   156.00,   -22.33,   0x4B48C8C8,   0x0 }
   [5]: { 168.77,   156.00,   14.65,   0x4B48C8C8,   0x0 }
   [6]: { 42.20,   63.00,   46.45,   0x4B48C8C8,   0x0 }
   [7]: { -50.37,   101.00,   20.83,   0x4B48C8C8,   0x0 }
   [8]: { 39.05,   63.00,   -59.62,   0x4B48C8C8,   0x0 }
   [9]: { -55.72,   101.00,   -16.27,   0x4B48C8C8,   0x0 }
   [10]: { 154.71,   126.00,   18.41,   0x4B48C8C8,   0x0 }
   [11]: { 152.46,   126.00,   -24.64,   0x4B48C8C8,   0x0 }
   [12]: { 34.56,   85.44,   -37.73,   0x4B48C8C8,   0x4 }
   [13]: { 38.75,   84.09,   26.33,   0x4B48C8C8,   0x3 }
   [14]: { -31.15,   161.00,   -20.30,   0x4B48C8C8,   0x6 }
   [15]: { -32.19,   161.00,   15.88,   0x4B48C8C8,   0x5 }
   [16]: { -43.02,   142.00,   0.95,   0x4B48C8C8,   0x2 }
   [17]: { -44.33,   89.00,   18.53,   0x4B48C8C8,   0x0 }
   [18]: { -52.26,   40.00,   14.39,   0x4B48C8C8,   0x0 }
   [19]: { -80.05,   64.00,   1.90,   0x4B48C8C8,   0x0 }
   [20]: { -69.02,   51.00,   0.09,   0x4B48C8C8,   0x0 }
   [21]: { -78.89,   64.00,   -7.08,   0x4B48C8C8,   0x0 }
   [22]: { -40.65,   89.00,   -20.42,   0x4B48C8C8,   0x0 }
   [23]: { -95.98,   56.00,   -2.38,   0x4B48C8C8,   0x0 }
   [24]: { -67.93,   51.00,   -4.89,   0x4B48C8C8,   0x0 }
   [25]: { -53.62,   40.00,   -22.64,   0x4B48C8C8,   0x0 }
   [26]: { -3.74,   -80.09,   2.38,   0x4B48C8C8,   0x0 }
   [27]: { 2.26,   -80.09,   4.38,   0x4B48C8C8,   0x0 }
   [28]: { 12.26,   -0.09,   10.38,   0x4B48C8C8,   0x0 }
   [29]: { -9.74,   -0.09,   5.38,   0x4B48C8C8,   0x0 }
   [30]: { 0.26,   -80.09,   -4.62,   0x4B48C8C8,   0x0 }
   [31]: { 8.26,   -0.09,   -5.62,   0x4B48C8C8,   0x0 }
   [32]: { -34.74,   -79.09,   -9.62,   0x4B48C8C8,   0x0 }
   [33]: { -29.74,   -80.09,   27.38,   0x4B48C8C8,   0x0 }
   [34]: { -51.74,   -80.09,   15.38,   0x4B48C8C8,   0x0 }
   [35]: { -3.53,   -81.44,   -0.30,   0x4B48C8C8,   0x0 }
   [36]: { 2.54,   -81.44,   -2.09,   0x4B48C8C8,   0x0 }
   [37]: { 12.74,   -1.44,   -7.73,   0x4B48C8C8,   0x0 }
   [38]: { -9.42,   -1.44,   -3.50,   0x4B48C8C8,   0x0 }
   [39]: { 8.19,   -1.44,   8.12,   0x4B48C8C8,   0x0 }
   [40]: { 0.23,   -81.44,   6.84,   0x4B48C8C8,   0x0 }
   [41]: { -33.82,   -80.44,   9.72,   0x4B48C8C8,   0x0 }
   [42]: { -27.75,   -81.44,   -25.02,   0x4B48C8C8,   0x0 }
   [43]: { -52.08,   -81.44,   -15.79,   0x4B48C8C8,   0x0 }
   [44]: { -1.40,   -30.00,   10.26,   0x4B48C8C8,   0x0 }
   [45]: { 55.14,   -54.00,   59.57,   0x4B48C8C8,   0x0 }
   [46]: { 144.93,   13.00,   73.10,   0x4B48C8C8,   0x0 }
   [47]: { 125.79,   -9.00,   78.90,   0x4B48C8C8,   0x0 }
   [48]: { 63.84,   32.00,   62.27,   0x4B48C8C8,   0x0 }
   [49]: { -1.56,   -30.00,   -3.79,   0x4B48C8C8,   0x0 }
   [50]: { 50.18,   -54.00,   -64.80,   0x4B48C8C8,   0x0 }
   [51]: { 125.79,   -9.00,   -85.75,   0x4B48C8C8,   0x0 }
   [52]: { 145.30,   13.00,   -77.79,   0x4B48C8C8,   0x0 }
   [53]: { 66.11,   32.00,   -61.42,   0x4B48C8C8,   0x0 }
}

// there is a DWORD here that specifies the number of quads - 1


quads[48] = {
   [0]:   { 0,   1,   2,   3,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [1]:   { 5,   4,   2,   1,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [2]:   { 22,   17,   0,   3,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [3]:   { 7,   6,   1,   0,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [4]:   { 9,   8,   6,   7,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [5]:   { 9,   3,   2,   8,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [6]:   { 10,   5,   1,   6,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [7]:   { 17,   18,   7,   0,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [8]:   { 3,   9,   25,   22,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [9]:   { 11,   8,   2,   4,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [10]:   { 5,   10,   11,   4,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [11]:   { 11,   10,   6,   8,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   1,   0}
   [12]:   { 18,   25,   9,   7,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [13]:   { 21,   19,   17,   22,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [14]:   { 19,   20,   18,   17,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [15]:   { 20,   24,   25,   18,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [16]:   { 24,   21,   22,   25,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   2,   0}
   [17]:   { 23,   23,   19,   21,   (0.35, 0.56),   (0.39,0.56),   (0.39,0.58),   (0.35,0.58)   1,   2,   0}
   [18]:   { 23,   23,   21,   24,   (0.35, 0.56),   (0.39,0.56),   (0.39,0.58),   (0.35,0.58)   1,   2,   0}
   [19]:   { 23,   23,   20,   19,   (0.35, 0.56),   (0.39,0.56),   (0.39,0.58),   (0.35,0.58)   1,   2,   0}
   [20]:   { 26,   27,   28,   29,   (0.36, 0.57),   (0.37,0.57),   (0.37,0.56),   (0.36,0.56)   1,   3,   0}
   [21]:   { 31,   30,   26,   29,   (0.36, 0.56),   (0.36,0.57),   (0.36,0.57),   (0.36,0.56)   1,   3,   0}
   [22]:   { 28,   27,   30,   31,   (0.37, 0.56),   (0.37,0.57),   (0.36,0.57),   (0.36,0.56)   1,   3,   0}
   [23]:   { 32,   32,   26,   30,   (0.36, 0.57),   (0.36,0.57),   (0.36,0.57),   (0.36,0.57)   1,   3,   0}
   [24]:   { 33,   33,   27,   26,   (0.36, 0.57),   (0.36,0.57),   (0.37,0.57),   (0.36,0.57)   1,   3,   0}
   [25]:   { 34,   34,   26,   30,   (0.37, 0.57),   (0.37,0.57),   (0.36,0.57),   (0.36,0.57)   1,   3,   0}
   [26]:   { 34,   34,   27,   26,   (0.37, 0.57),   (0.37,0.57),   (0.37,0.57),   (0.36,0.57)   1,   3,   0}
   [27]:   { 36,   35,   38,   37,   (0.37, 0.58),   (0.37,0.58),   (0.37,0.55),   (0.37,0.55)   1,   4,   0}
   [28]:   { 40,   39,   38,   35,   (0.37, 0.58),   (0.37,0.55),   (0.37,0.55),   (0.37,0.58)   1,   4,   0}
   [29]:   { 36,   37,   39,   40,   (0.37, 0.58),   (0.37,0.55),   (0.37,0.55),   (0.37,0.58)   1,   4,   0}
   [30]:   { 41,   41,   40,   35,   (0.38, 0.58),   (0.38,0.58),   (0.37,0.58),   (0.37,0.58)   1,   4,   0}
   [31]:   { 42,   42,   35,   36,   (0.37, 0.58),   (0.37,0.58),   (0.37,0.58),   (0.37,0.58)   1,   4,   0}
   [32]:   { 43,   43,   40,   35,   (0.37, 0.58),   (0.37,0.58),   (0.37,0.58),   (0.37,0.58)   1,   4,   0}
   [33]:   { 43,   43,   35,   36,   (0.37, 0.58),   (0.37,0.58),   (0.37,0.58),   (0.37,0.58)   1,   4,   0}
   [34]:   { 23,   23,   24,   20,   (0.35, 0.56),   (0.39,0.56),   (0.39,0.58),   (0.35,0.58)   1,   2,   0}
   [35]:   { 44,   45,   48,   0,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   5,   0}
   [36]:   { 47,   46,   48,   45,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   5,   0}
   [37]:   { 45,   48,   46,   47,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   5,   0}
   [38]:   { 44,   0,   48,   45,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   5,   0}
   [39]:   { 50,   49,   3,   53,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   6,   0}
   [40]:   { 53,   50,   51,   52,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   6,   0}
   [41]:   { 3,   49,   50,   53,   (0.00, 0.00),   (0.24,0.00),   (0.24,0.49),   (0.00,0.49)   0,   6,   0}
   [42]:   { 12,   12,   12,   12,   (0.00, 0.00),   (4.00,0.00),   (4.00,4.00),   (4.00,0.00)   0,   1,   128}
   [43]:   { 13,   13,   13,   13,   (0.00, 0.00),   (4.00,0.00),   (4.00,4.00),   (4.00,0.00)   0,   1,   128}
   [44]:   { 50,   53,   52,   51,   (0.24, 0.00),   (0.00,0.00),   (0.00,0.49),   (0.24,0.49)   0,   6,   0}
   [45]:   { 14,   14,   14,   14,   (0.00, 0.00),   (4.00,0.00),   (4.00,4.00),   (4.00,0.00)   0,   1,   128}
   [46]:   { 15,   15,   15,   15,   (0.00, 0.00),   (4.00,0.00),   (4.00,4.00),   (4.00,0.00)   0,   1,   128}
   [47]:   { 16,   16,   16,   16,   (0.00, 0.00),   (4.00,0.00),   (4.00,4.00),   (4.00,0.00)   0,   1,   128}
}

Summary:  3500 total bytes, 0 bytes left (should be 0)
54 vertices, 48 quads

Saving X-format file as "C:\Documents and Settings\Karl\My Documents\Volucris\Projects\MDJViewer\Debug\chicken.X"





Here's "mdjviewmain.cpp"
Code: Select all
#include "mdjview.h"

FILE* g_pOutputFile;

void output( char* pFormat, ... )
{
    va_list args;

    va_start( args, pFormat );
    char string[1024];
    vsprintf_s( string, sizeof(string), pFormat, args );
    va_end( args );

    printf( "%s", string );
    fprintf( g_pOutputFile, "%s", string );
    fflush( g_pOutputFile );
}


int run( int nArgs, char** ppArgs )
{
    printf( "MDJ Viewer by Karl is loading...\n" );

    // Check the number of arguments
    if( nArgs < 2 )
    {
        printf( "No file specified.\n" );
        return -1;
    }

    // debug line
    ppArgs[1] = "C:\\Documents and Settings\\Karl\\My Documents\\Volucris\\Projects\\MDJViewer\\Debug\\cauld.MDJ";

    // Print the name of the file being processed
    printf( "Reading MDJ model file \"%s\"\n", ppArgs[1] );

    // Create an X-file to save this as
    char xName[MAX_PATH];
    strcpy_s( xName, sizeof(xName), ppArgs[1] );
    int len = strlen(xName);
    xName[len-3]='X';
    xName[len-2]='\0';

    // Open the output file
    fopen_s( &g_pOutputFile, "output.txt", "wt" );

    // Open this file
    FILE* pFile;
    fopen_s( &pFile, ppArgs[1], "rb" );
    if( pFile == NULL )
    {
        output( "Unable to open file.\n" );
        return -1;
    }

    // Read the ID info
    DWORD fileType;
    fread( &fileType, sizeof(DWORD), 1, pFile );

    // Right now, only this file type can be decoded
    if( fileType == 50 )
    {
        DWORD header[52];
        fread( &header[1], sizeof(DWORD), 51, pFile );
        header[0] = fileType;
        pMDJHeader = header;

        // Print the header
        output( "header[52] = { " );
        for( DWORD i = 0; i < 52; ++i )
            output( "%i, ", header[i] );
        output( "}\n\n" );

        // Discover how many vertices there are
        DWORD vertices = header[51] + 1;

        // Create and fill in the vertex buffer
        output( "Reading %i vertices...", vertices );
        MDJVertex* pVB = new MDJVertex[vertices];
        fread( pVB, sizeof(MDJVertex), vertices, pFile );
        output( "success!\n" );

        // Read the number of quads ***note this might be a WORD followed by a WORD that is usually 0***
        DWORD quads;
        fread( &quads, sizeof(DWORD), 1, pFile );
        quads++; // This number is 1 less than it should be

        // Create and fill in the quad buffer
        output( "Reading %i quads...", quads );
        MDJQuad* pQB = new MDJQuad[quads];
        fread( pQB, sizeof(MDJQuad), quads, pFile );
        output( "success!\n" );

        // Print all of the information about the model's vertices
        output( "\n\nvertices[%i] = {\n", vertices );
        for( DWORD v = 0; v < vertices; ++v )
            output( "\t[%i]: { %.02f,\t%.02f,\t%.02f,\t0x%X,\t0x%X }\n", v, pVB[v].x, pVB[v].y, pVB[v].z, pVB[v].color, pVB[v].childBone );
        output( "}\n" );

        // Print all of the information about the model's quads
        output( "\n\nquads[%i] = {\n", quads );
        for( DWORD q = 0; q < quads; ++q )
            output("\t[%i]:\t{ %i,\t%i,\t%i,\t%i,\t"
                    "(%.02f, %.02f),\t(%.02f,%.02f),\t(%.02f,%.02f),\t(%.02f,%.02f)\t"
                    "%i,\t%i,\t%i}\n", q,
                                       pQB[q].indices[0], pQB[q].indices[1], pQB[q].indices[2], pQB[q].indices[3],
                                       pQB[q].texcoords[0], pQB[q].texcoords[1], pQB[q].texcoords[2], pQB[q].texcoords[3],
                                       pQB[q].texcoords[4], pQB[q].texcoords[5], pQB[q].texcoords[6], pQB[q].texcoords[7],
                                       pQB[q].tail[0], pQB[q].tail[1], pQB[q].tail[2] );
        output( "}\n" );

        // Output information about those interesting quad-tails!
        {
            DWORD numSubsets = 0, numTail0s = 0;

            for( DWORD q = 0; q <quads> numSubsets )
                    numSubsets = pQB[q].tail[1];
                if( pQB[q].tail[0] > numTail0s )
                    numTail0s = pQB[q].tail[0];
            }

            // Print bindings for the tail0-subsets (and just for kicks, print that index in the header)
            for( DWORD t0 = 0; t0 < numTail0s+1; ++t0 )
            {
                bool printedHeader = false;
                for( DWORD s = 0; s < numSubsets; ++s )
                {
                    DWORD occurances = 0;

                    for( DWORD q = 0; q <quads> 0 )
                    {
                        if( !printedHeader )
                        {
                            output( "\ntail[%i] = { ", t0 );
                            printedHeader = true;
                        }

                        output( "%i (%i), ", s, occurances );
                    }
                }
            }
        }

        // Print bytes left
        int readEnd = ftell( pFile );
        fseek( pFile, 0, SEEK_END );
        int end = ftell( pFile );
        output( "\n\nSummary:  %i total bytes, %i bytes left (should be 0)\n%i vertices, %i quads\n\n", end, end - readEnd, vertices, quads );

        output( "Saving X-format file as \"%s\"\n", xName );

        // Show the model
        display( xName, vertices, pVB, quads, pQB );

        // Erase the buffers
        delete[] pQB;
        delete[] pVB;
    }
    else if( fileType == 12866L )
    {
        // Start reading the header after we've read the type indicator
        MDJHeaderItem66 header[51];
        fread( header, sizeof(MDJHeaderItem66), 51, pFile );

        // Print the header
        output( "header[51] = { " );
        for( DWORD i = 0; i < 51; ++i )
            output( "0x%x 0x%X, ", header[i].value1byte, header[i].value4byte );
        output( "}\n\n" );

        // Discover how many vertices there are
        DWORD vertices = header[50].value4byte + 1;

        // Create and fill in the vertex buffer
        output( "Reading %i vertices...", vertices );
        MDJVertex66* pVB66 = new MDJVertex66[vertices];
        fread( pVB66, sizeof(MDJVertex66), vertices, pFile );
        output( "success!\n" );

        // Print all of the information about the model's vertices
        output( "\n\nvertices[%i] = {\n", vertices );
        for( DWORD v = 0; v < vertices; ++v )
            output( "\t[%i]: { %.02f,\t%.02f,\t%.02f,\t0x%X,\t0x%X, \t0x%X }\n", v, pVB66[v].x, pVB66[v].y, pVB66[v].z, pVB66[v].color, pVB66[v].zero, pVB66[v].value );
        output( "}\n" );

        // Convert to the normal vertex type (we might lose data here)
        MDJVertex* pVB = new MDJVertex[vertices];
        for( DWORD v = 0; v < vertices; ++v )
        {
            memcpy( &pVB[v], &pVB66[v], sizeof(MDJVertex) );
        }
        delete[] pVB66;

        // Read the number of quads ***note this might be a WORD followed by a WORD that is usually 0***
        DWORD quads;
        fread( &quads, sizeof(DWORD), 1, pFile );
        quads++; // This number is 1 less than it should be

        // Create and fill in the quad buffer
        output( "Reading %i quads...", quads );
        MDJQuad* pQB = new MDJQuad[quads];
        fread( pQB, sizeof(MDJQuad), quads, pFile );
        output( "success!\n" );

        // Print all of the information about the model's quads
        output( "\n\nquads[%i] = {\n", quads );
        for( DWORD q = 0; q < quads; ++q )
            output( "\t[%i]:\t{%i,\t%i,\t%i,\t%i, "
                    "\t(%.02f,%.02f), (%.02f,%.02f), (%.02f,%.02f), (%.02f,%.02f)"
                    " \t%i,\t%i,\t%i}\n", q, pQB[q].indices[0], pQB[q].indices[1], pQB[q].indices[2], pQB[q].indices[3],
                                       pQB[q].texcoords[0], pQB[q].texcoords[1], pQB[q].texcoords[2], pQB[q].texcoords[3],
                                       pQB[q].texcoords[4], pQB[q].texcoords[5], pQB[q].texcoords[6], pQB[q].texcoords[7],
                                       pQB[q].tail[0], pQB[q].tail[1], pQB[q].tail[2] );
        output( "}\n" );

        // Print bytes left
        int readEnd = ftell( pFile );
        fseek( pFile, 0, SEEK_END );
        int end = ftell( pFile );
        output( "\n\nSummary:  %i total bytes, %i bytes left (should be 0)\n%i vertices, %i quads\n\n", end, end - readEnd, vertices, quads );

        output( "Saving X-format file as \"%s\"\n", xName );

        // Show the model
        display( xName, vertices, pVB, quads, pQB );

        // Erase buffers
        delete[] pVB;
        delete[] pQB;
    }
    else
    {
        output( "Header indicates this is an unsupported file type.\n" );
        return -1;
    }

    // Close the file
    fclose( pFile );
    fclose( g_pOutputFile );

    // Success
    return 0;
}
#include <d3dx9>

// Entry point to the application
int main( int nArgs, char** ppArgs )
{

    // Execute the app
    int c = run( nArgs, ppArgs );

    // Wait for something to happen
    system("PAUSE");

    // Return the code
    return c;
}



Here's "mdjview.h"
Code: Select all
#include <windows>
#include <stdio>


#pragma pack( push, 1 ) // Don't pack here--we need these sizes to be exact
struct MDJVertex
{
    FLOAT x, y, z;
    DWORD color;
    DWORD childBone;
};

struct MDJQuad
{
    WORD indices[4];
    FLOAT texcoords[8];
    WORD tail[3]; // tail[0] is the TEXTURE FOR THIS MESH
                  // tail[1] is the animation subset for the mesh
                  // tail[2] is ?
};

struct MDJHeaderItem66
{
    BYTE value1byte;
    DWORD value4byte;
};

struct MDJVertex66
{
    FLOAT x, y, z;
    DWORD color;
    DWORD zero;
    BYTE value;
};


#pragma pack(pop)

extern DWORD* pMDJHeader;

void output( char* pFormat, ... );
void display( const char* pFileNameX, DWORD vertices, MDJVertex* pVertices, DWORD quads, MDJQuad* pQuads );



And (finally!) here's display.cpp
Code: Select all
#include "mdjview.h"
#include <Windows>
#include <mmsystem>
#include <d3dx9>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe>
#pragma warning( default : 4996 )
#include <string>
#include <vector>

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
LPDIRECT3D9             g_pD3D           = NULL; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice     = NULL; // Our rendering device

LPD3DXMESH              g_pMesh          = NULL; // Our mesh object in sysmem
D3DMATERIAL9*           g_pMeshMaterials = NULL; // Materials for our mesh

LPDIRECT3DTEXTURE9*     g_pMeshTextures  = NULL; // Textures for our mesh
DWORD                   g_dwNumTextures  = 0L;   // Number of mesh materials
DWORD* pMDJHeader = NULL;

FLOAT g_Height = 1.0f;
DWORD g_CurrentSubset = 0;
bool g_bShowAll = true;

DWORD g_CurrentTexture = 0;


struct MeshVertex
{
    FLOAT x, y, z;
    D3DCOLOR color;
    FLOAT u, v;
};

#define D3DFVF_MESHVERTEX (D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1)



//-----------------------------------------------------------------------------
// Name: InitD3D()
// Desc: Initializes Direct3D
//-----------------------------------------------------------------------------
HRESULT InitD3D( HWND hWnd )
{
    // Create the D3D object.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

    // Set up the structure used to create the D3DDevice. Since we are now
    // using more complex geometry, we will create a device with a zbuffer.
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory( &d3dpp, sizeof(d3dpp) );
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    // Create the D3DDevice
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                                      &d3dpp, &g_pd3dDevice ) ) )
    {
        return E_FAIL;
    }

    // Turn on the zbuffer
    g_pd3dDevice->SetRenderState( D3DRS_ZENABLE, TRUE );

    // Turn on ambient lighting
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING, FALSE );
    g_pd3dDevice->SetRenderState( D3DRS_AMBIENT, 0xffffffff );

    return S_OK;
}




//-----------------------------------------------------------------------------
// Name: InitGeometry()
// Desc: Load the mesh and build the material and texture arrays
//-----------------------------------------------------------------------------
HRESULT InitGeometry( const char* pFileNameX, DWORD vertices, MDJVertex* pVertices, DWORD quads, MDJQuad* pQuads, FLOAT* pRadius )
{
    FLOAT maxRadiusSq = 0.0f;

    // Find all of the texture files in the directory
    {
        std::vector<std> textures;
        WIN32_FIND_DATA data;
        ZeroMemory( &data, sizeof(data) );
        HANDLE hFind = FindFirstFile( "*.png", &data );
        if( data.nFileSizeLow > 0 )
        {
            do
            {
                textures.push_back( data.cFileName );
            }
            while( FindNextFile( hFind, &data ) );

            // Create a texture bank
            g_pMeshTextures = new LPDIRECT3DTEXTURE9[textures.size()];
            g_dwNumTextures = (DWORD)textures.size();

            // Load each texture
            DWORD index = 0;
            for( std::vector<std>::iterator i = textures.begin(); i != textures.end(); ++i, ++index )
            {
                D3DXCreateTextureFromFile( g_pd3dDevice, i->c_str(), &g_pMeshTextures[index] );
            }
        }
    }


/*
    // Generate the mesh vertex structure
    if( FAILED( D3DXCreateMeshFVF( quads * 2, vertices, 0, D3DFVF_MESHVERTEX, g_pd3dDevice, &g_pMesh ) ) )
        return E_FAIL;

    // Lock the buffers
    MeshVertex* pMeshVertices = NULL;
    WORD* pMeshIndices = NULL;
    if( SUCCEEDED( g_pMesh->LockVertexBuffer( 0, (VOID**)&pMeshVertices ) ) &&
        SUCCEEDED( g_pMesh->LockIndexBuffer( 0, (VOID**)&pMeshIndices ) ) )
    {
        // Build the vertices
        for( DWORD v = 0; v <vertices> maxRadiusSq )
                maxRadiusSq = radiusSq;

            pMeshVertices[v].color = pVertices[v].color;
            pMeshVertices[v].u = 0.0f;
            pMeshVertices[v].v = 0.0f;
        }

        WORD* p = pMeshIndices;

        // Build the indices
        for( DWORD q = 0; q <quads>UnlockIndexBuffer();
        g_pMesh->UnlockVertexBuffer();
    }
    else
        return E_FAIL;
*/

    // Generate the mesh vertex structure
    if( FAILED( D3DXCreateMeshFVF( quads * 2, quads * 4, 0, D3DFVF_MESHVERTEX, g_pd3dDevice, &g_pMesh ) ) )
        return E_FAIL;

    // Lock the buffers
    MeshVertex* pMeshVertices = NULL;
    WORD* pMeshIndices = NULL;
    if( SUCCEEDED( g_pMesh->LockVertexBuffer( 0, (VOID**)&pMeshVertices ) ) &&
        SUCCEEDED( g_pMesh->LockIndexBuffer( 0, (VOID**)&pMeshIndices ) ) )
    {
        DWORD currentVertexIndex = 0;

        MeshVertex* pMeshVerticesStart = pMeshVertices;
        WORD* pMeshIndicesStart = pMeshIndices;

        // Build the vertices
        for( DWORD q = 0; q < quads; ++q )
        {
            DWORD startIndex = currentVertexIndex;

            // Repeat for each vertex in the quad
            for( DWORD v = 0; v <4>x = pVertex->x;
                pMeshVertices->y = pVertex->y;
                pMeshVertices->z = pVertex->z;

                // Keep track of the radius of the model (assuming origin-centric)
                FLOAT radiusSq = pMeshVertices->x * pMeshVertices->x + pMeshVertices->y * pMeshVertices->y + pMeshVertices->z * pMeshVertices->z;
                if( radiusSq > maxRadiusSq )
                    maxRadiusSq = radiusSq;

                pMeshVertices->color = 0xFFFFFFFF;//pVertex->color;
                pMeshVertices->u = pQuads[q].texcoords[v*2+0];
                pMeshVertices->v = pQuads[q].texcoords[v*2+1];

                currentVertexIndex++;
                pMeshVertices++;
            }

            pMeshIndices[0] = startIndex + 0;
            pMeshIndices[1] = startIndex + 1;
            pMeshIndices[2] = startIndex + 2;
            pMeshIndices[3] = startIndex + 0;
            pMeshIndices[4] = startIndex + 2;
            pMeshIndices[5] = startIndex + 3;
            pMeshIndices += 6;
        }

        // Save this file as a .X mesh using a fake material
        D3DXMATERIAL mtrl;
        ZeroMemory( &mtrl, sizeof(mtrl) );
        if( FAILED( D3DXSaveMeshToX( pFileNameX, g_pMesh, NULL, &mtrl, NULL, 1, D3DXF_FILEFORMAT_TEXT ) ) )
        {
            output( "NOTE:  Unable to save mesh" );
        }

        DWORD* pMeshAttr = NULL;
        if( SUCCEEDED( g_pMesh->LockAttributeBuffer( 0, &pMeshAttr ) ) )
        {
            DWORD* pMeshAttrStart = pMeshAttr;
            // Assign mesh attributes based on data from the quad info
            for( DWORD q = 0; q < quads; ++q )
            {
                // Weeee
                pMeshAttr[0] = pQuads[q].tail[0];
                pMeshAttr[1] = pQuads[q].tail[0];
                pMeshAttr+=2;
            }

            // Woot! Bone Matrices!
            //D3DXMATRIXA16 bones[50];
            //for( int i = 0; i < 50; ++i )
            //    D3DXMatrixIdentity( &bones[i] );

            // Go through and find quads with the last tail component set to 128
            // With these, look in the vertices they reference for transformation coordinates
            // Find attributes (bones) with the same last-value as those vertices and transform them accordingly
            if( false ) // this only works for the chicken, because it has no recursion and is SLOPPY
            for( DWORD q = 0; q <quads> 1 ) g_CurrentSubset--; else { if( g_CurrentSubset == 0 ) g_bShowAll = true; else g_CurrentSubset = 0; }
            if( wParam == 'q' ) if( g_CurrentTexture > 1 ) g_CurrentTexture--; else g_CurrentTexture = 0;
            if( wParam == 'e' ) if( g_CurrentTexture + 1 <g_dwNumTextures>GetDeviceCaps( &caps );
        DWORD v = caps.MaxVertexShaderConst;
        v = v;


        FLOAT modelRadius = 0.0f;

        // Create the scene geometry
        if( SUCCEEDED( InitGeometry( pFileNameX, vertices, pVertices, quads, pQuads, &modelRadius ) ) )
        {
            // Show the window
            ShowWindow( hWnd, SW_SHOWDEFAULT );
            UpdateWindow( hWnd );

            // Enter the message loop
            MSG msg;
            ZeroMemory( &msg, sizeof(msg) );
            while( msg.message!=WM_QUIT )
            {
                if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
                {
                    TranslateMessage( &msg );
                    DispatchMessage( &msg );
                }
                else
                    Render( modelRadius );
            }
        }

        Cleanup();
    }

    UnregisterClass( "D3D Tutorial", wc.hInstance );
}
User avatar
Karl G.
Lesser Spirit
 
Posts: 2453
Joined: Sat Mar 04, 2006 10:26 am

Postby Xodus » Mon Apr 02, 2007 4:34 pm

That's good stuff. I just have to crack open my book so I can understand it hehe. :)

Thanks and keep up the good work.
Xodus
Villager
Villager
 
Posts: 6
Joined: Thu Dec 21, 2006 11:26 pm

Postby Karl G. » Mon Apr 02, 2007 4:37 pm

No problem. If you send me an email (karlgluck@gmail.com) I can zip up the working project and email it to you.

Karl
User avatar
Karl G.
Lesser Spirit
 
Posts: 2453
Joined: Sat Mar 04, 2006 10:26 am

Postby Xodus » Mon Apr 02, 2007 4:48 pm

Sent.
Xodus
Villager
Villager
 
Posts: 6
Joined: Thu Dec 21, 2006 11:26 pm


Return to Volucris



Who is online

Users browsing this forum: No registered users and 1 guest