• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            永遠也不完美的程序

            不斷學習,不斷實踐,不斷的重構……

            常用鏈接

            統(tǒng)計

            積分與排名

            好友鏈接

            最新評論

            MDL file format (Quake's models)

            link:http://tfc.duke.free.fr/coding/mdl-specs-en.html
            Written by David Henry, 20th December of 2004

            Introduction

            The MDL file format is the model format used in Quake (June 1996). MDL model files' characteristics are these:

            • Model's geometric data (triangles);
            • 8 bits texture data;
            • Frame-by-frame animations;

            A MDL file can hold multiple textures.

            MDL model file's extension is “mdl”. A MDL file is a binary file divided in two part: the header dans the data. The header contains all information needed to use and manipulate the data.

            Header
            Data

            Variable sizes

            Variable types used in this document have those sizes:

            • char: 1 byte
            • short: 2 bytes
            • int: 4 bytes
            • float: 4 bytes
            • ubyte: 1 unsigned byte

            They correspond to C type sizes on the x86 architecture. Ensure that type sizes correspond to these ones if you're compiling for another architecture.

            Endianess issues

            Since the MDL file format is a binary format, you'll have to deal with endianess. MDL files are stored in little-endian (x86). If you're targetting a big-endian architecture (PowerPC, SPARC, ...), or simply want your program to be portable, you'll have to perform proper conversions for each word or double word read from the file.

            The header

            The header is a structure which comes at the beginning of the file:

            /* MDL header */
            struct mdl_header_t
            {
            int ident;            /* magic number: "IDPO" */
            int version;          /* version: 6 */
            vec3_t scale;         /* scale factor */
            vec3_t translate;     /* translation vector */
            float boundingradius;
            vec3_t eyeposition;   /* eyes' position */
            int num_skins;        /* number of textures */
            int skinwidth;        /* texture width */
            int skinheight;       /* texture height */
            int num_verts;        /* number of vertices */
            int num_tris;         /* number of triangles */
            int num_frames;       /* number of frames */
            int synctype;         /* 0 = synchron, 1 = random */
            int flags;            /* state flag */
            float size;
            };

            ident is the magic number of the file. It is used to identify the file type. ident must be equal to 1330660425 or to the string “IDPO”. We can obtain this number with the expression (('2'<<24) + ('P'<<16) + ('D'<<8) + 'I').

            version is the version number of the file format and must be equal to 6.

            scale and translate are needed to obtain the real vertex coordinates of the model. scale is a scale factor and translate a translation vector (or the origin of the model). You have to first multiply the respective value of scale with the vertex coordinate and then, add the respective value of translate to the result:

            vreal[i] = (scale[i] * vertex[i]) + translate[i];

            where i ranges from 0 ou 2 (x, y and z coordinates).

            boundingradius is the radius of a sphere in which the whole model can fit (used for collision detection for exemple).

            eyeposition is... eyes' position (if the model is for a monster or other NPC). Make what you want of it.

            num_skins is the number of textures present in the file. skinwidth and skinheight are respectively the with and height of the textures. All textures must have the same size.

            num_verts is the number of vertices of one frame.
            num_tris is the number of triangles of the model.
            num_frames is the number of frames of the model.

            Data types

            Vector

            The vector, composed of three floating coordinates (x, y, z):

            /* Vector */
            typedef float vec3_t[3];

            Texture information

            Texture data come right after the header in the file. It can be a texture composed of a single picture or a group of pictures (animated texture).

            /* Skin */
            struct mdl_skin_t
            {
            int group;      /* 0 = single, 1 = group */
            GLubyte *data;  /* texture data */
            };

            or:

            /* Group of pictures */
            struct mdl_groupskin_t
            {
            int group;     /* 1 = group */
            int nb;        /* number of pics */
            float *time;   /* time duration for each pic */
            ubyte **data;  /* texture data */
            };

            time is an array of nb elements and data an array of nb arrays of skinwidth * skinheight elements (picture size).

            Data pictures are contained in the data array and are in 8 bits color index mode. The colormap is generally in a separate LMP file (*.lmp). LMP files are binary files which contain only 768 bytes (256 colors in 24 bits). They are easy to use: just read the whole file in a buffer and it's done.

            A colormap is avalaible in texte format.

            There are num_skins objects of mdl_skin_t type or mdl_groupskin_t type.

            Texture coordinates

            Texture coordinates are stored in a structure as short integers.

            /* Texture coords */
            struct mdl_texcoord_t
            {
            int onseam;
            int s;
            int t;
            };

            Texture are generally divided in two pieces: one for the frontface of the model, and one for the backface. The backface piece must be translated of skinwidth/2 from the frontface piece.

            onseam indicates if the vertex is on the boundary of two pieces.

            To obtain real (s, t) coordinates (ranging from 0.0 to 1.0), you have to add 0.5 to the coordinates and then divide the result by skinwidth for s and skinheight for t.

            There are num_verts (s, t) texture coordinates in a MDL model. Texture coordinate data come after texture data.

            Triangles

            Each triangle has an array of vertex indices and a flag to indicate if it is a frontface or a backface triangle.

            /* Triangle info */
            struct mdl_triangle_t
            {
            int facesfront;  /* 0 = backface, 1 = frontface */
            int vertex[3];   /* vertex indices */
            };

            If a vertex which belong to a backface triangle is on the boundary of two pieces (onseam is true), you have to add skinwidth/2 to s in order to correct texture coordinates.

            There are num_tris triangles in a MDL model. Triangle data follow texture coord. data in the file.

            Vertices

            Vertices are composed of “compressed” 3D coordinates, which are stored in one byte for each coordinate, and of a normal vector index. The normal vector array is stored in the anorms.h file of Quake and hold 162 vectors in floating point (3 float).

            /* Compressed vertex */
            struct mdl_vertex_t
            {
            unsigned char v[3];
            unsigned char normalIndex;
            };

            Frames

            Each frames has its vertex list and some other specific informations.

            /* Simple frame */
            struct mdl_simpleframe_t
            {
            struct mdl_vertex_t bboxmin; /* bouding box min */
            struct mdl_vertex_t bboxmax; /* bouding box max */
            char name[16];
            struct mdl_vertex_t *verts;  /* vertex list of the frame */
            };

            bboxmin and bboxmax define a box in which the model can fit. name is the name of the frame. verts is the vertex list of the frame.

            Frames can be simple frames or groups of frames. We can know if it's a simple frame or a group with a flag:

            /* Model frame */
            struct mdl_frame_t
            {
            int type;                        /* 0 = simple, !0 = group */
            struct mdl_simpleframe_t frame;  /* this program can't read models
            composed of group frames! */
            };

            or:

            /* Group of simple frames */
            struct mdl_groupframe_t
            {
            int type;                         /* !0 = group */
            struct mdl_vertex_t min;          /* min pos in all simple frames */
            struct mdl_vertex_t max;          /* max pos in all simple frames */
            float *time;                      /* time duration for each frame */
            struct mdl_simpleframe_t *frames; /* simple frame list */
            };

            time and frames are arrays of nb dimension. min and max correspond to the min and max positions in all simple frames of the frame group. time is the duration of each simple frame.

            There are num_frames frames in a MDL model. Frames come after triangle data in the MDL file.

            Reading a MDL file

            Assuming that mdl_model_t is a structure holding all your model's data and *mdl a pointer on a mdl_model_t object, this code show how to load a MDL model file:

            int
            ReadMDLModel (const char *filename, struct mdl_model_t *mdl)
            {
            FILE *fp;
            int i;
            fp = fopen (filename, "rb");
            if (!fp)
            {
            fprintf (stderr, "error: couldn't open \"%s\"!\n", filename);
            return 0;
            }
            /* Read header */
            fread (&mdl->header, 1, sizeof (struct mdl_header_t), fp);
            if ((mdl->header.ident != 1330660425) ||
            (mdl->header.version != 6))
            {
            /* Error! */
            fprintf (stderr, "Error: bad version or identifier\n");
            fclose (fp);
            return 0;
            }
            /* Memory allocations */
            mdl->skins = (struct mdl_skin_t *)
            malloc (sizeof (struct mdl_skin_t) * mdl->header.num_skins);
            mdl->texcoords = (struct mdl_texcoord_t *)
            malloc (sizeof (struct mdl_texcoord_t) * mdl->header.num_verts);
            mdl->triangles = (struct mdl_triangle_t *)
            malloc (sizeof (struct mdl_triangle_t) * mdl->header.num_tris);
            mdl->frames = (struct mdl_frame_t *)
            malloc (sizeof (struct mdl_frame_t) * mdl->header.num_frames);
            mdl->tex_id = (GLuint *)
            malloc (sizeof (GLuint) * mdl->header.num_skins);
            mdl->iskin = 0;
            /* Read texture data */
            for (i = 0; i < mdl->header.num_skins; ++i)
            {
            mdl->skins[i].data = (GLubyte *)malloc (sizeof (GLubyte)
            * mdl->header.skinwidth * mdl->header.skinheight);
            fread (&mdl->skins[i].group, sizeof (int), 1, fp);
            fread (mdl->skins[i].data, sizeof (GLubyte),
            mdl->header.skinwidth * mdl->header.skinheight, fp);
            mdl->tex_id[i] = MakeTextureFromSkin (i, mdl);
            free (mdl->skins[i].data);
            mdl->skins[i].data = NULL;
            }
            fread (mdl->texcoords, sizeof (struct mdl_texcoord_t),
            mdl->header.num_verts, fp);
            fread (mdl->triangles, sizeof (struct mdl_triangle_t),
            mdl->header.num_tris, fp);
            /* Read frames */
            for (i = 0; i < mdl->header.num_frames; ++i)
            {
            /* Memory allocation for vertices of this frame */
            mdl->frames[i].frame.verts = (struct mdl_vertex_t *)
            malloc (sizeof (struct mdl_vertex_t) * mdl->header.num_verts);
            /* Read frame data */
            fread (&mdl->frames[i].type, sizeof (long), 1, fp);
            fread (&mdl->frames[i].frame.bboxmin,
            sizeof (struct mdl_vertex_t), 1, fp);
            fread (&mdl->frames[i].frame.bboxmax,
            sizeof (struct mdl_vertex_t), 1, fp);
            fread (mdl->frames[i].frame.name, sizeof (char), 16, fp);
            fread (mdl->frames[i].frame.verts, sizeof (struct mdl_vertex_t),
            mdl->header.num_verts, fp);
            }
            fclose (fp);
            return 1;
            }

            Note: this code can't handle MDL files with group frames.

            Rendering the model

            Here is an exemple of how to draw a frame n of a model mdl:

            void
            RenderFrame (int n, const struct mdl_model_t *mdl)
            {
            int i, j;
            GLfloat s, t;
            vec3_t v;
            struct mdl_vertex_t *pvert;
            /* Check if n is in a valid range */
            if ((n < 0) || (n > mdl->header.num_frames - 1))
            return;
            /* Enable model's texture */
            glBindTexture (GL_TEXTURE_2D, mdl->tex_id[mdl->iskin]);
            /* Draw the model */
            glBegin (GL_TRIANGLES);
            /* Draw each triangle */
            for (i = 0; i < mdl->header.num_tris; ++i)
            {
            /* Draw each vertex */
            for (j = 0; j < 3; ++j)
            {
            pvert = &mdl->frames[n].frame.verts[mdl->triangles[i].vertex[j]];
            /* Compute texture coordinates */
            s = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].s;
            t = (GLfloat)mdl->texcoords[mdl->triangles[i].vertex[j]].t;
            if (!mdl->triangles[i].facesfront &&
            mdl->texcoords[mdl->triangles[i].vertex[j]].onseam)
            {
            s += mdl->header.skinwidth * 0.5f; /* Backface */
            }
            /* Scale s and t to range from 0.0 to 1.0 */
            s = (s + 0.5) / mdl->header.skinwidth;
            t = (t + 0.5) / mdl->header.skinheight;
            /* Pass texture coordinates to OpenGL */
            glTexCoord2f (s, t);
            /* Normal vector */
            glNormal3fv (anorms_table[pvert->normalIndex]);
            /* Calculate real vertex position */
            v[0] = (mdl->header.scale[0] * pvert->v[0]) + mdl->header.translate[0];
            v[1] = (mdl->header.scale[1] * pvert->v[1]) + mdl->header.translate[1];
            v[2] = (mdl->header.scale[2] * pvert->v[2]) + mdl->header.translate[2];
            glVertex3fv (v);
            }
            }
            glEnd ();
            }

            Animation

            MDL models are frame-by-frame animated. A frame is a screenshot of an animation. To avoid jerked and ugly animations, we use linear interpolation between vertex coordinates of two consecutive frames (the current frame we are drawing and the next frame). We do the same for the normal vector:

            struct mdl_vertex_t *pvert1, *pvert2;
            vec3_t v;
            for (/* ... */)
            {
            pvert1 = &mdl->frames[current].frame.verts[mdl->triangles[i].vertex[j]];
            pvert2 = &mdl->frames[current + 1].frame.verts[mdl->triangles[i].vertex[j]];
            /* ... */
            v[0] = mdl->header.scale[0] * (pvert1->v[0] + interp * (pvert2->v[0] - pvert1->v[0])) + mdl->header.translate[0];
            v[1] = mdl->header.scale[1] * (pvert1->v[1] + interp * (pvert2->v[1] - pvert1->v[1])) + mdl->header.translate[1];
            v[2] = mdl->header.scale[2] * (pvert1->v[2] + interp * (pvert2->v[2] - pvert1->v[2])) + mdl->header.translate[2];
            /* ... */
            }

            v is the final vertex to draw. interp is the interpolation percent between the two frames. It's a float which ranges from 0.0 to 1.0. When it is equal to 1.0, current is incremented by 1 and interp is reinitialized at 0.0. It is useless to interpolate texture coordinates because they are the same for all the model frames. It is preferable that interp is related to the program's number of rendering frame per second (fps).

            void
            Animate (int start, int end, int *frame, float *interp)
            {
            if ((*frame < start) || (*frame > end))
            *frame = start;
            if (*interp >= 1.0f)
            {
            /* Move to next frame */
            *interp = 0.0f;
            (*frame)++;
            if (*frame >= end)
            *frame = start;
            }
            }

            Constants

            Here are some constant values defining maximal dimensions:

            • Maximum number of triangles: 2048
            • Maximum number of vertices: 1024
            • Maximum number of texture coordinates: 1024
            • Maximum number of frames: 256
            • Number of precalculated normal vectors: 162

            posted on 2008-11-04 15:51 狂爛球 閱讀(1187) 評論(0)  編輯 收藏 引用 所屬分類: 圖形編程

            久久伊人五月丁香狠狠色| 久久精品国产亚洲av麻豆色欲| 国内高清久久久久久| 97久久婷婷五月综合色d啪蜜芽| 亚洲中文字幕无码久久2017| AV无码久久久久不卡蜜桃| 精品少妇人妻av无码久久| 精品国产91久久久久久久a| 久久噜噜久久久精品66| 亚洲人成伊人成综合网久久久| 国产精品一久久香蕉国产线看观看 | 久久91这里精品国产2020| 日日狠狠久久偷偷色综合免费 | 亚洲成av人片不卡无码久久| 久久综合给合久久狠狠狠97色| 国产精品久久久久久久午夜片 | 午夜精品久久久久久影视777| 亚洲综合日韩久久成人AV| 91精品国产乱码久久久久久 | 国产精品久久久久蜜芽| 久久精品成人免费网站| 国产69精品久久久久观看软件 | 久久久久亚洲AV成人网人人网站 | 日韩精品无码久久一区二区三| 久久久久国产精品熟女影院| 人妻系列无码专区久久五月天| 久久亚洲高清观看| 99久久久国产精品免费无卡顿| 99精品国产免费久久久久久下载 | 欧美精品国产综合久久| 99热成人精品免费久久| 久久精品亚洲中文字幕无码麻豆| 久久综合九色综合欧美就去吻| 亚洲成人精品久久| 国内精品久久国产大陆| 成人国内精品久久久久一区| 亚洲精品无码久久久影院相关影片| 亚洲国产成人精品女人久久久 | 久久久婷婷五月亚洲97号色| 亚洲国产另类久久久精品小说 | 精品久久久久久无码专区不卡|