topameng's profileQuake3 启示录PhotosBlogListsMore Tools Help

Blog


    May 20

    顶点坐标变换

    转载请注明出处 http://topameng.spaces.live.com
    通过坐标变换将3D空间的图元转换成2D图元的过程:主要为世界变换->视图变换->投影变换->视口变换
    3D场景中的任何物体,都是由一个一个三角形组成的。而三角形位置信息的就是其各个顶点的三维坐标。这是用来在模型中存储的,而要把物体显示在屏幕上,还需要将它们转换成显示器上的二维坐标。这就需要对每个点实施一套 3D to 2D 的转换公式,在Direct3D中叫做“几何流水线”(Geometry Pipeline)。
    一般创建的mesh处于自己的局部坐标系。基本是屏幕正中放置。
    世界矩阵:而游戏需要先放入世界坐标系。世界坐标系主要3大功能:平移、旋转、缩放
    平移:  D3DXMatrixTranslation() 位于矩阵第四行
    1   0   0   0
    0   1   0   0
    0   0   1   0
    Tx Ty Tz  1

    旋转: D3DXMatrixRotationX()  延 x 轴旋转
    1    0    0    0
    0  cos  sin   0
    0 -sin   cos  0
    0    0    0    1
    D3DXMatrixRotationY()  延 y 轴旋转
    cos 0  -sin   0
    0    1    0    0
    sin  0   cos  0
    0    0    0    1
    D3DXMatrixRotationZ()  延 z 轴旋转
    cos sin   0   0
    -sin cos  0  0
    0    0    1    0
    0    0    0    1
    缩放: D3DXMatrixScaling

    顺序如先旋转R在缩放S 则矩阵为 R*S 。对于行向量(dx默认为行向量)复合矩阵视觉效果为从左到右的顺序各单独矩阵效果的组合。对于列向量则相反: 复合矩阵应为 S * R.视觉效果从右到左(这是opengl 采用的)

    观察矩阵:函数 D3DXMatrixLookAtLH()
    不要被这个函数吓倒。其实观察矩阵作用和世界矩阵差不多,只是起到旋转、平移的作用。而且是把世界坐标系的物体映射到观察坐标系。只要用摄像机当前世界变换矩阵的逆就好了
    矩阵基本组成 M = T*Rz*Ry*Rz 。 T 平移。 Rz 延z旋转。Ry 延Y旋转 Rx 延X轴旋转
    实际上可以先获得摄像机的世界坐标 p,和摄像机坐标系轴在世界坐标中的矢量D(看向),U(上),R(右)。然后要把世界坐标的摄像机位置点换算到摄像机局部坐标系中。 (-D * p, - U * p, - R * p)  计算-p 在(D,U,R)矢量上的投影转换为p1.
    Dx, Ux,  Rx,  0
    Dy, Uy,  Ry, 0
    Dz, Uz,  Rz,  0
    p1x,p1yp1z, 1

    对于D,U,R 其实就是摄像机的世界坐标旋转变换的逆矩阵。如下:
    Dx,Dy,Dz
    Ux,Uy,Uz
    Rx,Ry,Rz
    旋转矩阵(还有镜像矩阵)为正交矩阵(参考3D数学基础中的矩阵正交化章节)。对于一个正交矩阵他的逆矩阵等于转置矩阵

    这些不会影响mesh 的顶点和法线关系
    使用shader时。如计算顶点和法线的点积,没必要映射到观察坐标系.在 direct3d 游戏编程基础的 shader 章节里。顶点法线和光线矢量都映射到了视图空间。其实是没有必要的

    而世界变化和观察变换是可以和到一起组成世界-视图变换矩阵

    投影变换:把3d 投影到2d平面(似乎说映射[-1,-1,0(opengl 为-1)] 到[1,1,1]的立方体更好一些。但透视投影相当于3D变换成2D,近大远小的变换就在这个时刻)分为透视投影和正交投影。正交投影不会随物体远近影响物体投影的大小。而透视则z值影响,物体越远成像越小。
    投影变换涉及缩放和平移操作。对于正交投影矩阵缩放和z值无关。对于透视投影缩放和z值相关。
    对于dx 左手坐标系函数如下:

    正交投影函数:
    D3DXMatrixOrthoLH() 这个是以屏幕中心为坐标原点的。
    如果设置2d坐标系。 可以考虑使用 D3DXMatrixOrthoOffCenterLH 函数
    D3DXMatrixOrthoOffCenterLH(&m_matProj,0,(float)m_iWidth,(float)m_iHeight,0,0.0f,1.0f);
    这样左上角为坐标(0,0). 右下角为(width,height)
    透视投影:
    D3DXMatrixPerspectiveFovLH()
    对于Opengl经过投影变换x,y,z映射到范围[-1,1]. x,y 还保持原来的符号。对于z 最远面 f 映射为1,最近面 n 映射为 -1.
    但directx z 值略有差异。z 映射范围为[0,1]。最远面映射为1。最近面映射为0.
    对于z值都是以 1/z 映射到 [0,1]或者[-1,1] 范围。因为一般要求近处z值判断要精细一些。而远处精度要小一些。所以用1/z来判断更好。
    一个dx 投影矩阵如下: w,h 为 zn 面的宽度和高度。zn 近表面距离。zf 为远表面。

    2*zn/w  0       0              0
    0       2*zn/h  0              0
    0       0       zf/(zf-zn)     1
    0       0       zn*zf/(zn-zf)  0


    其次坐标一个点p(px,py,pz,1) 经过这个变化成为(x'pz,y'pz,z'pz,pz)

    dx 一直透视投影函数一直默认了中心点为[0,0] (摄像机坐标x,y). 如果视景截头体不以[0,0]为中心则需要自己生成投影矩阵。
    如对于zn平面,左l 右 r 上 t 下 b.这样 w = r - l  h = t - b .建立的非对称投影矩阵如下(相对于dx左手坐标,对于opengl略有不同)

    2*zn/r-l  0         0              0
    0         2*zn/t-b  0              0
    r+l/r-l   t+b/t-b   zf/(zf-zn)     1
    0         0         zn*zf/(zn-zf)  0



    dx 采用的是行向量,对于一个矢量 v 变换相当于  v * T.  而不是 T * v
    opengl 采用的是列向量, 对于矢量变化为 T * v

    左手坐标系和右手坐标系平移、缩放矩阵是相同的。
    对于旋转矩阵,输入角度时有变化:
    从轴的负端向正端看,左手坐标系  逆时针为正方向。即逆时针延z旋转旋转30 度。输入正数30 到旋转矩阵.
    而右手坐标系相反,逆时针为负方向。即逆时针延z旋转30度。输入-30 到旋转矩阵

    用U0 U1 U2 表示变换矩阵, 对于矩阵 R(U0 | U1 | U2)
    对于右手坐标 U0 = U1 X U2   U1 = U2 X U0 U2 = U0 X U1
    对于左手坐标 U0 = U2 X U1   U1 = U0 X U2 U2 = U1 X U0

    而有些系统如gamebryo 采用右手坐标系但是Gamebryo矩阵旋转方向和默认右手坐标系相反,我日。gb 延旋转轴顺时针为正。好处换成左手不用修改矩阵了。悲伤

    尽管有这些左右顺序问题。 但很多放在内存中矩阵结构是一样的。这是为了方便使用intel SSE加速指令。
    dx 矩阵存放结构
    struct {
            float        _11, _12, _13, _14;   
            float        _21, _22, _23, _24;
            float        _31, _32, _33, _34;
            float        _41, _42, _43, _44;
    };

    May 14

    编译 Nvidia Sdk

    出现Incorrect version of Direct3D and/or D3DX 错误
    在nvidia 使用的dxut.lib 中有针对dx编译版本与运行版本的比较。
    D3DXCheckVersion(D3D_SDK_VERSION, D3DX_SDK_VERSION)
    只需要重新编译LIBS\src\DXUT工程即可

    May 13

    何为引擎?

    最早的概念差不多来自ID吧,quake.exe 就是引擎。而客户端只是玩法逻辑部分,现在随着时代发展似乎在悄悄的变化。很多引擎现在只提供库,并没有winmain函数。而很多人认为winmain属于客户端的范畴。
    winmain所在的项目可以起一个Fade的概念。q3 是这样,renderer 功能是图形lib, quake3 工程导出了renderer 和 quake3 工程中的资源管理部分函数,给其他工程使用,这样减少了耦合,UI、renderer 和 game 工程都只和quake3工程单线联系。这似乎比客户端概念多了点东西
    想到把这个概念引入到后面项目中。
    领导认为这样会导致大量重复代码? 如果需求多导出接口会过多.
    当时没仔细想,毕竟工程没有开始,这方面不好意思跟领导吹牛。
    想想quake3 的导出函数也不是很多,很多图形相关的主要就2个函数:如shader
    registershader ()  drawshader()  (不是q3函数,类似名字)
    模型和场景类也差不多。
    而shader非常复杂。接口却很少,其实很简单,那就是配置文件,注册的名字在配置文件中,而配置文件描述了这个名字对应的shader的各个技术特性,如果这些特性也导出函数接口,将是非常复杂的工程。
    看来开放mod是非常有好处的。要考虑给各个档次的人使用。
    相关的图形导出函数简直少的可怜(10,20还是30,懒得数了所有接口的也就100左右,还包含众多资源函数控制台cvar,甚至ping之类的),却能实现异常复杂的功能。
    尽管q3引擎已经落伍了,但看它的代码还是能有非常多的收获的。可惜就是应用太窄了(室内引擎不太适合网络游戏),其实quake完全可是胜任室外,以前光从表面看,有些认知错误

    gamebryo 也是建议开发者修改NiApplication.这样的话NiApplication 工程相当与引擎主工程有整个进程起点winmain。而客户端逻辑相对放入dll。
    quake3 shader 和 现在d9 的 shader 概念是不太一样的。请勿对号入座

    April 25

    The MDX file format 1

    不好搜到了。备份一份在blog
    The MDX file format!
    Compiled by Magnus Ostberg (aka Magos)
    MagosX@GMail.com

    //+-----------------------------------------------------------------------------
    //| Data types
    //+-----------------------------------------------------------------------------
    CHAR   - 8bit character
    BYTE   - 8bit unsigned integer
    WORD   - 16bit unsigned integer
    DWORD  - 32bit unsigned integer
    FLOAT  - 32bit floating point number
    FLOAT2 - 2-dimensional floating point vector (elements ordered as x, y)
    FLOAT3 - 3-dimensional floating point vector (elements ordered as x, y, z or b, g, r)
    FLOAT4 - 4-dimensional floating point vector (elements ordered as x, y, z, w)
    X[n]   - An n-dimensional vector of type X

    //+-----------------------------------------------------------------------------
    //| Descriptions
    //+-----------------------------------------------------------------------------
    ChunkSize     - ChunkSize is the size of the whole structure *NOT*
                    including the tag and size itself. As an example,
                    the chunksize of the Version structure is 4.

    InclusiveSize - InclusiveSize is the size of the structure including
                    the size of the InclusiveSize variable.

    ExclusiveSize - ExclusiveSize is the size of the structure *NOT*
                    including the size of the ExclusiveSize variable.

    {X};          - A structure that may or may not be present. They
                    may also be in a different order than specified.

    X;            - A structure that must be present and in the
                    specified order.

    #X            - A flag value, more than one can be combined.

    //+-----------------------------------------------------------------------------
    //| Notes
    //+-----------------------------------------------------------------------------
    - All ID's (ObjectId, ParentId, GlobalSequenceId, TextureAnimationId, etc...)
      can use the special value 0xFFFFFFFF to represent 'no ID'.

    - Some ID's (GeosetId, etc...) can use the special value 0xFFFFFFFF to
      represent 'multiple IDs'.

    - All colors are stored as BGR, not RGB!

    //+-----------------------------------------------------------------------------
    //| MDX Model structure
    //+-----------------------------------------------------------------------------
    struct MdxModel
    {
      DWORD 'MDLX';

      {VersionChunk};
      {ModelChunk};
      {SequenceChunk};
      {GlobalSequenceChunk};
      {TextureChunk};
      {TextureAnimationChunk};
      {GeosetChunk};
      {GeosetAnimationChunk};
      {BoneChunk};
      {LightChunk};
      {HelperChunk};
      {AttachmentChunk};
      {PivotPointChunk};
      {ParticleEmitterChunk};
      {ParticleEmitter2Chunk};
      {RibbonEmitterChunk};
      {EventObjectChunk};
      {CameraChunk};
      {CollisionShapeChunk};
    };

    //+-----------------------------------------------------------------------------
    //| Animated geoset translation
    //+-----------------------------------------------------------------------------
    struct GeosetTranslation
    {
      DWORD 'KGTR';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Translation;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated geoset rotation
    //+-----------------------------------------------------------------------------
    struct GeosetRotation
    {
      DWORD 'KGRT';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct RotationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT4 Rotation;

        if(InterpolationType > 1)
        {
          FLOAT4 InTan;
          FLOAT4 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated geoset scaling
    //+-----------------------------------------------------------------------------
    struct GeosetScaling
    {
      DWORD 'KGSC';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Scaling;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated geoset alpha
    //+-----------------------------------------------------------------------------
    struct GeosetAlpha
    {
      DWORD 'KGAO';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Alpha;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated geoset color
    //+-----------------------------------------------------------------------------
    struct GeosetColor
    {
      DWORD 'KGAC';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Color;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated texture translation
    //+-----------------------------------------------------------------------------
    struct TextureTranslation
    {
      DWORD 'KTAT';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Translation;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated texture rotation
    //+-----------------------------------------------------------------------------
    struct TextureRotation
    {
      DWORD 'KTAR';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT4 Rotation;

        if(InterpolationType > 1)
        {
          FLOAT4 InTan;
          FLOAT4 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated texture scaling
    //+-----------------------------------------------------------------------------
    struct TextureScaling
    {
      DWORD 'KTAS';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Scaling;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated camera position translation
    //+-----------------------------------------------------------------------------
    struct CameraPositionTranslation
    {
      DWORD 'KCTR';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Translation;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated camera target translation
    //+-----------------------------------------------------------------------------
    struct CameraTargetTranslation
    {
      DWORD 'KTTR';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Translation;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated camera rotation
    //+-----------------------------------------------------------------------------
    struct CameraRotation
    {
      DWORD 'KCRL';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct TranslationTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Rotation;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated material texture ID
    //+-----------------------------------------------------------------------------
    struct MaterialTextureId
    {
      DWORD 'KMTF';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        DWORD TextureId;

        if(InterpolationType > 1)
        {
          DWORD InTan;
          DWORD OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated material alpha
    //+-----------------------------------------------------------------------------
    struct MaterialAlpha
    {
      DWORD 'KMTA';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Alpha;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated attachment visibility
    //+-----------------------------------------------------------------------------
    struct AttachmentVisibility
    {
      DWORD 'KATV';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Visibility;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated light visibility
    //+-----------------------------------------------------------------------------
    struct LightVisibility
    {
      DWORD 'KLAV';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Visibility;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated light color
    //+-----------------------------------------------------------------------------
    struct LightColor
    {
      DWORD 'KLAC';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 Color;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated light intensity
    //+-----------------------------------------------------------------------------
    struct LightIntensity
    {
      DWORD 'KLAI';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Intensity;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated light ambient color
    //+-----------------------------------------------------------------------------
    struct LightAmbientColor
    {
      DWORD 'KLBC';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT3 AmbientColor;

        if(InterpolationType > 1)
        {
          FLOAT3 InTan;
          FLOAT3 OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated light ambient intensity
    //+-----------------------------------------------------------------------------
    struct LightAmbientIntensity
    {
      DWORD 'KLBI';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT AmbientIntensity;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter visibility
    //+-----------------------------------------------------------------------------
    struct ParticleEmitterVisibility
    {
      DWORD 'KPEV';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Visibility;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter 2 visibility
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2Visibility
    {
      DWORD 'KP2V';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Visibility;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter 2 emission rate
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2EmissionRate
    {
      DWORD 'KP2E';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT EmissionRate;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter 2 width
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2Width
    {
      DWORD 'KP2W';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Width;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter 2 length
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2Length
    {
      DWORD 'KP2N';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Length;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    The MDX file format 2

    //+-----------------------------------------------------------------------------
    //| Animated particle emitter 2 speed
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2Speed
    {
      DWORD 'KP2S';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Speed;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated ribbon emitter visibility
    //+-----------------------------------------------------------------------------
    struct RibbonEmitterVisibility
    {
      DWORD 'KRVS';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT Visibility;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated ribbon emitter height above
    //+-----------------------------------------------------------------------------
    struct RibbonEmitterHeightAbove
    {
      DWORD 'KRHA';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT HeightAbove;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Animated ribbon emitter height below
    //+-----------------------------------------------------------------------------
    struct RibbonEmitterHeightBelow
    {
      DWORD 'KRHB';

      DWORD NrOfTracks;
      DWORD InterpolationType;             //0 - None
                                           //1 - Linear
                                           //2 - Hermite
                                           //3 - Bezier
      DWORD GlobalSequenceId;

      struct ScalingTrack[NrOfTracks]
      {
        DWORD Time;
        FLOAT HeightBelow;

        if(InterpolationType > 1)
        {
          FLOAT InTan;
          FLOAT OutTan;
        }
      };
    };

    //+-----------------------------------------------------------------------------
    //| Node (the base for some of the objects)
    //+-----------------------------------------------------------------------------
    struct Node
    {
      DWORD InclusiveSize;

      CHAR[80] Name;

      DWORD ObjectId;
      DWORD ParentId;
      DWORD Flags;                         //0        - Helper
                                           //#1       - DontInheritTranslation
                                           //#2       - DontInheritRotation
                                           //#4       - DontInheritScaling
                                           //#8       - Billboarded
                                           //#16      - BillboardedLockX
                                           //#32      - BillboardedLockY
                                           //#64      - BillboardedLockZ
                                           //#128     - CameraAnchored
                                           //#256     - Bone
                                           //#512     - Light
                                           //#1024    - EventObject
                                           //#2048    - Attachment
                                           //#4096    - ParticleEmitter
                                           //#8192    - CollisionShape
                                           //#16384   - RibbonEmitter
                                           //#32768   - Unshaded / EmitterUsesMdl
                                           //#65536   - SortPrimitivesFarZ / EmitterUsesTga
                                           //#131072  - LineEmitter
                                           //#262144  - Unfogged
                                           //#524288  - ModelSpace
                                           //#1048576 - XYQuad

      {GeosetTranslation}
      {GeosetRotation}
      {GeosetScaling}
    };

    //+-----------------------------------------------------------------------------
    //| Version information
    //+-----------------------------------------------------------------------------
    struct VersionChunk
    {
      DWORD 'VERS';
      DWORD ChunkSize;

      DWORD Version;                       //Currently 800
    };

    //+-----------------------------------------------------------------------------
    //| Model information
    //+-----------------------------------------------------------------------------
    struct ModelChunk
    {
      DWORD 'MODL';
      DWORD ChunkSize;

      CHAR[80] Name;
      CHAR[260] AnimationFileName;

      FLOAT BoundsRadius;
      FLOAT3 MinimumExtent;
      FLOAT3 MaximumExtent;
      DWORD BlendTime;
    };

    //+-----------------------------------------------------------------------------
    //| Sequences
    //+-----------------------------------------------------------------------------
    struct SequenceChunk
    {
      DWORD 'SEQS';
      DWORD ChunkSize;

      struct Sequence[NrOfSequences]       //NrOfSequences = ChunkSize / 132
      {
        CHAR[80] Name;

        DWORD IntervalStart;
        DWORD IntervalEnd;
        FLOAT MoveSpeed;
        DWORD Flags;                       //0 - Looping
                                           //1 - NonLooping
        FLOAT Rarity;
        DWORD SyncPoint;

        FLOAT BoundsRadius;
        FLOAT3 MinimumExtent;
        FLOAT3 MaximumExtent;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Global sequences
    //+-----------------------------------------------------------------------------
    struct GlobalSequenceChunk
    {
      DWORD 'GLBS';
      DWORD ChunkSize;

      struct GlobalSequence[NrOfGlobalSequences]  //NrOfGlobalSequences = ChunkSize / 4
      {
        DWORD Duration;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Textures
    //+-----------------------------------------------------------------------------
    struct TextureChunk
    {
      DWORD 'TEXS';
      DWORD ChunkSize;

      struct Texture[NrOfTextures]         //NrOfTextures = ChunkSize / 268
      {
        DWORD ReplaceableId;

        CHAR[260] FileName;
        DWORD Flags;                       //#1 - WrapWidth
                                           //#2 - WrapHeight
      };
    };

    //+-----------------------------------------------------------------------------
    //| Layers
    //+-----------------------------------------------------------------------------
    struct LayerChunk
    {
      DWORD 'LAYS';
      DWORD NrOfLayers;

      struct Layer[NrOfLayers]
      {
        DWORD InclusiveSize;

        DWORD FilterMode;                  //0 - None
                                           //1 - Transparent
                                           //2 - Blend
                                           //3 - Additive
                                           //4 - AddAlpha
                                           //5 - Modulate
                                           //6 - Modulate2x

        DWORD ShadingFlags;                //#1   - Unshaded
                                           //#2   - SphereEnvironmentMap
                                           //#4   - ???
                                           //#8   - ???
                                           //#16  - TwoSided
                                           //#32  - Unfogged
                                           //#64  - NoDepthTest
                                           //#128 - NoDepthSet

        DWORD TextureId;
        DWORD TextureAnimationId;
        DWORD CoordId;
        FLOAT Alpha;

        {MaterialAlpha}
        {MaterialTextureId}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Materials
    //+-----------------------------------------------------------------------------
    struct MaterialChunk
    {
      DWORD 'MTLS';
      DWORD ChunkSize;

      struct Material[NrOfMaterials]
      {
        DWORD InclusiveSize;

        DWORD PriorityPlane;
        DWORD Flags;                       //#1  - ConstantColor
                                           //#2  - ???
                                           //#4  - ???
                                           //#8  - SortPrimitivesNearZ
                                           //#16 - SortPrimitivesFarZ
                                           //#32 - FullResolution

        {LayerChunk}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Texture animations
    //+-----------------------------------------------------------------------------
    struct TextureAnimationChunk
    {
      DWORD 'TXAN';
      DWORD ChunkSize;

      struct TextureAnimation[NrOfTextureAnimations]
      {
        DWORD InclusiveSize;

        {TextureTranslation}
        {TextureRotation}
        {TextureScaling}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Geosets
    //+-----------------------------------------------------------------------------
    struct GeosetChunk
    {
      DWORD 'GEOS';
      DWORD ChunkSize;

      struct Geoset[NrOfGeosets]
      {
        DWORD InclusiveSize;

        DWORD 'VRTX';
        DWORD NrOfVertexPositions;

        struct VertexPosition[NrOfVertexPositions]
        {
          FLOAT3 Position;
        };

        DWORD 'NRMS';
        DWORD NrOfVertexNormals;

        struct VertexNormal[NrOfVertexNormals]
        {
          FLOAT3 Normal;
        };

        DWORD 'PTYP';
        DWORD NrOfFaceTypeGroups;

        struct FaceTypeGroup[NrOfFaceTypeGroups]
        {
          DWORD FaceType;                  //4   - Triangles
                                           //??? - Triangle fan
                                           //??? - Triangle strip
                                           //??? - Quads
                                           //??? - Quad strip
        };

        DWORD 'PCNT';
        DWORD NrOfFaceGroups;

        struct FaceGroup[NrOfFaceGroups]
        {
          DWORD NrOfIndexes;
        };

        DWORD 'PVTX';
        DWORD TotalNrOfIndexes;

        struct Face[TotalNrOfFaces]        //TotalNrOfFaces = TotalNrOfIndexes / 3
        {
          WORD Index1;
          WORD Index2;
          WORD Index3;
        };

        DWORD 'GNDX';
        DWORD NrOfVertexGroups;

        struct VertexGroup[NrOfVertexGroups]
        {
          BYTE MatrixGroup;
        };

        DWORD 'MTGC';
        DWORD NrOfMatrixGroups;

        struct MatrixGroup[NrOfMatrixGroups]
        {
          DWORD MatrixGroupSize;
        };

        DWORD 'MATS';
        DWORD NrOfMatrixIndexes;

        struct MatrixIndex[NrOfMatrixIndexes]
        {
          DWORD MatrixIndex;
        };

        DWORD MaterialId;
        DWORD SelectionGroup;
        DWORD SelectionFlags;              //0  - None
                                           //#1 - ???
                                           //#2 - ???
                                           //#4 - Unselectable

        FLOAT BoundsRadius;
        FLOAT3 MinimumExtent;
        FLOAT3 MaximumExtent;

        DWORD NrOfExtents;

        struct Extent[NrOfExtents]
        {
          FLOAT3 MinimumExtent;
          FLOAT3 MaximumExtent;
        };

        DWORD 'UVAS';
        DWORD NrOfTextureVertexGroups;

        DWORD 'UVBS';
        DWORD NrOfVertexTexturePositions;

        struct VertexTexturePosition[NrOfVertexTexturePositions]
        {
          FLOAT2 TexturePosition;
        };
      };
    };

    //+-----------------------------------------------------------------------------
    //| Geoset animations
    //+-----------------------------------------------------------------------------
    struct GeosetAnimationChunk
    {
      DWORD 'GEOA';
      DWORD ChunkSize;

      struct GeosetAnimation[NrOfGeosetAnimations]
      {
        DWORD InclusiveSize;

        FLOAT Alpha;
        DWORD Flags;                       //#1 - DropShadow
                                           //#2 - Color
        FLOAT3 Color;

        DWORD GeosetId;

        {GeosetAlpha}
        {GeosetColor}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Bones
    //+-----------------------------------------------------------------------------
    struct BoneChunk
    {
      DWORD 'BONE';
      DWORD ChunkSize;

      struct Bone[NrOfBones]
      {
        Node;

        DWORD GeosetId;
        DWORD GeosetAnimationId;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Lights
    //+-----------------------------------------------------------------------------
    struct LightChunk
    {
      DWORD 'LITE';
      DWORD ChunkSize;

      struct Light[NrOfLights]
      {
        DWORD InclusiveSize;

        Node;

        DWORD Type;                        //0 - Omnidirectional
                                           //1 - Directional
                                           //2 - Ambient
        DWORD AttenuationStart;
        DWORD AttenuationEnd;
        FLOAT3 Color;
        FLOAT Intensity;
        FLOAT3 AmbientColor;
        FLOAT AmbientIntensity;

        {LightVisibility}
        {LightColor}
        {LightIntensity}
        {LightAmbientColor}
        {LightAmbientIntensity}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Helpers
    //+-----------------------------------------------------------------------------
    struct HelperChunk
    {
      DWORD 'HELP';
      DWORD ChunkSize;

      struct Helper[NrOfHelpers]
      {
        Node;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Attachments
    //+-----------------------------------------------------------------------------
    struct AttachmentChunk
    {
      DWORD 'ATCH';
      DWORD ChunkSize;

      struct Attachment[NrOfAttachments]
      {
        DWORD InclusiveSize;

        Node;

        CHAR[260] Path;
        DWORD AttachmentId;                //First attachment - 0, second - 1 etc...

        {AttachmentVisibility}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Pivot points
    //+-----------------------------------------------------------------------------
    struct PivotPointChunk
    {
      DWORD 'PIVT';
      DWORD ChunkSize;

      struct PivotPoint[NrOfPivotPoints]   //NrOfPivotPoints = ChunkSize / 12
      {
        FLOAT3 Position;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Particle emitters
    //+-----------------------------------------------------------------------------
    struct ParticleEmitterChunk
    {
      DWORD 'PREM';
      DWORD ChunkSize;

      struct ParticleEmitter[NrOfParticleEmitters]
      {
        DWORD InclusiveSize;

        Node;

        FLOAT EmissionRate;
        FLOAT Gravity;
        FLOAT Longitude;
        FLOAT Latitude;

        CHAR[260] SpawnModelFileName;

        FLOAT LifeSpan;
        FLOAT InitialVelocity;

        {ParticleEmitterVisibility}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Particle emitters 2
    //+-----------------------------------------------------------------------------
    struct ParticleEmitter2Chunk
    {
      DWORD 'PRE2';
      DWORD ChunkSize;

      struct ParticleEmitter2[NrOfParticleEmitters2]
      {
        DWORD InclusiveSize;

        Node;

        FLOAT Speed;
        FLOAT Variation;
        FLOAT Latitude;
        FLOAT Gravity;
        FLOAT Lifespan;
        FLOAT EmissionRate;
        FLOAT Length;
        FLOAT Width;

        DWORD FilterMode;                  //0 - Blend
                                           //1 - Additive
                                           //2 - Modulate
                                           //3 - Modulate2x
                                           //4 - AlphaKey

        DWORD Rows;
        DWORD Columns;
        DWORD HeadOrTail;                  //0 - Head
                                           //1 - Tail
                                           //2 - Both

        FLOAT TailLength;
        FLOAT Time;

        FLOAT3[3] SegmentColor;
        BYTE[3] SegmentAlpha;
        FLOAT[3] SegmentScaling;

        DWORD HeadIntervalStart
        DWORD HeadIntervalEnd
        DWORD HeadIntervalRepeat
        DWORD HeadDecayIntervalStart
        DWORD HeadDecayIntervalEnd
        DWORD HeadDecayIntervalRepeat
        DWORD TailIntervalStart
        DWORD TailIntervalEnd
        DWORD TailIntervalRepeat
        DWORD TailDecayIntervalStart
        DWORD TailDecayIntervalEnd
        DWORD TailDecayIntervalRepeat

        DWORD TextureId;
        DWORD Squirt;                      //0 - No Squirt
                                           //1 - Squirt
        DWORD PriorityPlane;
        DWORD ReplaceableId;

        {ParticleEmitter2Visibility}
        {ParticleEmitter2EmissionRate}
        {ParticleEmitter2Width}
        {ParticleEmitter2Length}
        {ParticleEmitter2Speed}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Ribbon emitters
    //+-----------------------------------------------------------------------------
    struct RibbonEmitterChunk
    {
      DWORD 'RIBB';
      DWORD ChunkSize;

      struct RibbonEmitter[NrOfRibbonEmitters]
      {
        DWORD InclusiveSize;

        Node;

        FLOAT HeightAbove;
        FLOAT HeightBelow;
        FLOAT Alpha;
        FLOAT3 Color;
        FLOAT LifeSpan;

        DWORD TextureSlot;

        DWORD EmissionRate;
        DWORD Rows;
        DWORD Columns;
        DWORD MaterialId;
        FLOAT Gravity;

        {RibbonEmitterVisibility}
        {RibbonEmitterHeightAbove}
        {RibbonEmitterHeightBelow}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Tracks
    //+-----------------------------------------------------------------------------
    struct Tracks
    {
      DWORD 'KEVT';
      DWORD NrOfTracks;

      DWORD GlobalSequenceId;

      struct Track[NrOfTracks]
      {
        DWORD Time;
      };
    };

    //+-----------------------------------------------------------------------------
    //| Event objects
    //+-----------------------------------------------------------------------------
    struct EventObjectChunk
    {
      DWORD 'EVTS';
      DWORD ChunkSize;

      struct EventObject[NrOfEventObjects]
      {
        Node;

        {Tracks}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Cameras
    //+-----------------------------------------------------------------------------
    struct CameraChunk
    {
      DWORD 'CAMS';
      DWORD ChunkSize;

      struct Camera[NrOfCameras]
      {
        DWORD InclusiveSize;

        CHAR[80] Name;

        FLOAT3 Position;
        DWORD FieldOfView;
        DWORD FarClippingPlane;
        DWORD NearClippingPlane;
        FLOAT3 TargetPosition;

        {CameraPositionTranslation}
        {CameraTargetTranslation}
      };
    };

    //+-----------------------------------------------------------------------------
    //| Collision shapes
    //+-----------------------------------------------------------------------------
    struct CollisionShapeChunk
    {
      DWORD 'CLID';
      DWORD ChunkSize;

      struct CollisionShape[NrOfCollisionShapes]
      {
        Node;

        DWORD Type;                        //0 - Box
                                           //1 - ???
                                           //2 - Sphere

                                           //NrOfVertices = 2 (if Type == 0)
        struct Vertex[NrOfVertices]        //NrOfVertices = 1 (if Type == 2)
        {
          FLOAT3 Position;
        };

        if(Type == 2)
        {
          FLOAT BoundsRadius;
        }
      };
    };