Beispiel #1
0
        /// <summary>
        /// Загрузка MD2 из файла
        /// </summary>
        /// <param name="fname">Имя файла</param>
        /// <returns>Собранный меш</returns>
        public static Entity Load(string fname)
        {
            // Загрузка модели
            string f = fname.ToLower();

            if (!loaded.ContainsKey(f))
            {
                loaded.Add(f, ReadModel(fname));
            }
            MorphMeshComponent me = loaded[f];

            // Создание объекта
            Entity e = new Entity();

            e.AddComponent(new MorphMeshComponent()
            {
                Proxy = me
            });
            e.AddComponent(new AnimatorComponent());

            // Возврат
            return(e);
        }
Beispiel #2
0
        /// <summary>
        /// Чтение модели с диска, если она не закеширована
        /// </summary>
        /// <param name="fname">Имя файла</param>
        /// <returns>Кешированная модель</returns>
        static MorphMeshComponent ReadModel(string fname)
        {
            // Открытие файла
            byte[]       data = FileSystem.Read(fname);
            BinaryReader f    = new BinaryReader(new MemoryStream(data));

            // Чтение заголовка
            string fourcc  = new string(f.ReadChars(4));
            int    version = f.ReadInt32();

            if (fourcc != "IDP2" || version != 8)
            {
                f.Close();
                return(null);
            }

            // Размер текстуры и одного кадра
            float skinWidth  = f.ReadInt32();
            float skinHeight = f.ReadInt32();
            int   frameSize  = f.ReadInt32();

            // Чтение размеров и отступов
            f.BaseStream.Position += 4;
            int vertexNum   = f.ReadInt32();
            int texCoordNum = f.ReadInt32();
            int trisNum     = f.ReadInt32();

            f.BaseStream.Position += 4;
            int frameNum = f.ReadInt32();

            f.BaseStream.Position += 4;
            int texCoordOffset = f.ReadInt32();
            int trisOffset     = f.ReadInt32();
            int frameOffset    = f.ReadInt32();

            // Чтение текстурных координат
            Vec2[] texCoords = new Vec2[texCoordNum];
            f.BaseStream.Position = texCoordOffset;
            for (int i = 0; i < texCoordNum; i++)
            {
                texCoords[i].X = (float)f.ReadInt16() / skinWidth;
                texCoords[i].Y = (float)f.ReadInt16() / skinHeight;
            }

            // Чтение треугольников
            ushort[] indices    = new ushort[trisNum * 3];
            ushort[] coordAssoc = new ushort[trisNum * 3];
            f.BaseStream.Position = trisOffset;
            for (int i = 0; i < trisNum; i++)
            {
                int tri = i * 3;
                indices[tri + 0]    = f.ReadUInt16();
                indices[tri + 1]    = f.ReadUInt16();
                indices[tri + 2]    = f.ReadUInt16();
                coordAssoc[tri + 0] = f.ReadUInt16();
                coordAssoc[tri + 1] = f.ReadUInt16();
                coordAssoc[tri + 2] = f.ReadUInt16();
            }

            // Чтение кадров
            Vec3[][] verts = new Vec3[frameNum][];
            Vec3[][] norms = new Vec3[frameNum][];
            f.BaseStream.Position = frameOffset;
            for (int fr = 0; fr < frameNum; fr++)
            {
                // Создание массивов
                verts[fr] = new Vec3[vertexNum];
                norms[fr] = new Vec3[vertexNum];

                // Размер и позиция
                float sx, sy, sz, ox, oy, oz;
                sx = f.ReadSingle();
                sy = f.ReadSingle();
                sz = f.ReadSingle();
                ox = f.ReadSingle();
                oy = f.ReadSingle();
                oz = f.ReadSingle();

                // Имя кадра
                f.BaseStream.Position += 16;

                // Чтение вершин
                for (int vr = 0; vr < vertexNum; vr++)
                {
                    // Чтение вершины
                    float px, py, pz;
                    px            = (float)f.ReadByte() * sx + ox;
                    py            = (float)f.ReadByte() * sy + oy;
                    pz            = (float)f.ReadByte() * sz + oz;
                    verts[fr][vr] = new Vec3(-py, pz, px) * 0.015f;

                    // Чтение нормали
                    byte nidx = f.ReadByte();
                    Vec3 nv   = normalList[nidx];
                    norms[fr][vr] = new Vec3(-nv.Y, nv.Z, nv.X);
                }
            }
            f.Close();

            // Теперь, из-за того, что имеет место использование
            // одних и тех же вершин, но с разными текстурными
            // координатами, требуется создать копии для каждой
            // вершины под свои координаты

            // Поиск всех использованных текстурных координат каждой вершиной
            int totalVerts = 0;

            List <int>[] usedCoords = new List <int> [vertexNum];
            for (int i = 0; i < indices.Length; i++)
            {
                if (usedCoords[indices[i]] == null)
                {
                    usedCoords[indices[i]] = new List <int>();
                }
                if (!usedCoords[indices[i]].Contains(coordAssoc[i]))
                {
                    usedCoords[indices[i]].Add(coordAssoc[i]);
                    totalVerts++;
                }
            }

            // Заполнение массива ассоциаций вершин и текстурных координат
            Vec2[] coords      = new Vec2[totalVerts];
            int[]  vertexAssoc = new int[totalVerts];
            int    assocIndex  = 0;
            int    vertexIndex = 0;

            foreach (List <int> il in usedCoords)
            {
                for (int i = 0; i < il.Count; i++)
                {
                    vertexAssoc[assocIndex + i] = vertexIndex;
                    coords[assocIndex + i]      = texCoords[il[i]];
                }
                assocIndex += il.Count;
                vertexIndex++;
            }

            // Перестройка массива индексов
            for (int i = 0; i < indices.Length; i++)
            {
                int idx = 0;
                int tex = coordAssoc[i];
                foreach (List <int> ac in usedCoords)
                {
                    if (ac.Contains(tex))
                    {
                        idx += ac.IndexOf(tex);
                        break;
                    }
                    idx += ac.Count;
                }
                indices[i] = (ushort)idx;
            }

            // Перестройка кадров
            MorphMeshComponent.Frame[] morphFrames = new MorphMeshComponent.Frame[frameNum];
            for (int fr = 0; fr < frameNum; fr++)
            {
                // Переассоциация вершин
                Vec3[] frameVerts = new Vec3[totalVerts];
                Vec3[] frameNorms = new Vec3[totalVerts];
                for (int vr = 0; vr < totalVerts; vr++)
                {
                    frameVerts[vr] = verts[fr][vertexAssoc[vr]];
                    frameNorms[vr] = norms[fr][vertexAssoc[vr]];
                }

                // Создание кадра
                MorphMeshComponent.MorphFrame frame = new MorphMeshComponent.MorphFrame();
                frame.Time      = fr;
                frame.Vertices  = frameVerts;
                frame.Normals   = frameNorms;
                morphFrames[fr] = frame;
            }

            // Создание компонента
            MorphMeshComponent mmesh = new MorphMeshComponent();

            mmesh.TexCoords = coords;
            mmesh.Indices   = indices;
            mmesh.Frames    = morphFrames;

            return(mmesh);
        }
Beispiel #3
0
        /// <summary>
        /// Чтение модели с диска, если она не закеширована
        /// </summary>
        /// <param name="fname">Имя файла</param>
        /// <returns>Кешированная модель</returns>
        static CachedEntry ReadModel(string fname)
        {
            // Открытие файла
            byte[]       data = FileSystem.Read(fname);
            BinaryReader f    = new BinaryReader(new MemoryStream(data));

            // Чтение заголовка
            string fourcc  = new string(f.ReadChars(4));
            int    version = f.ReadInt32();

            if (fourcc != "IDP3" || version != 15)
            {
                f.Close();
                return(null);
            }

            // Пропуск имени модели и флагов
            f.BaseStream.Position += 72;

            // Значения количества
            int tagNum     = f.ReadInt32();
            int surfaceNum = f.ReadInt32();

            // Пропуск скинов
            f.BaseStream.Position += 8;

            // Отступы в файле
            int tagOffset     = f.ReadInt32();
            int surfaceOffset = f.ReadInt32();

            // Кешированная запись
            CachedEntry entry = new CachedEntry();

            // Массивы мешей
            entry.Surfaces = new MorphMeshComponent[surfaceNum];

            // Чтение поверхностей
            f.BaseStream.Position = surfaceOffset;
            for (int surfIndex = 0; surfIndex < surfaceNum; surfIndex++)
            {
                // Пропуск ненужных данных
                f.BaseStream.Position += 72;

                // Чтение размеров
                int frameNum    = f.ReadInt32();
                int shaderNum   = f.ReadInt32();
                int vertexNum   = f.ReadInt32();
                int triangleNum = f.ReadInt32();

                // Пропуск отступов и шейдеров
                f.BaseStream.Position += 20;
                f.BaseStream.Position += 68 * shaderNum;

                // Индексы
                ushort[] indices = new ushort[triangleNum * 3];
                for (int i = 0; i < indices.Length; i++)
                {
                    indices[i] = (ushort)f.ReadInt32();
                }

                // Текстурные координаты
                Vec2[] texCoords = new Vec2[vertexNum];
                for (int i = 0; i < texCoords.Length; i++)
                {
                    texCoords[i].X = f.ReadSingle();
                    texCoords[i].Y = f.ReadSingle();
                }

                // Кадры
                MorphMeshComponent.MorphFrame[] frames = new MorphMeshComponent.MorphFrame[frameNum];
                for (int frameIndex = 0; frameIndex < frameNum; frameIndex++)
                {
                    // Необходимые массивы
                    Vec3[] verts = new Vec3[vertexNum];
                    Vec3[] norms = new Vec3[vertexNum];

                    // Чтение вершин и нормалей
                    for (int i = 0; i < vertexNum; i++)
                    {
                        // Позиция
                        float px, py, pz, nx, ny, nz;
                        px       = (float)f.ReadInt16() * VERTEX_SCALE;
                        py       = (float)f.ReadInt16() * VERTEX_SCALE;
                        pz       = (float)f.ReadInt16() * VERTEX_SCALE;
                        verts[i] = new Vec3(-py, pz, px);

                        // Нормаль
                        float lng = (float)f.ReadByte() * NORMAL_MULT;
                        float lat = (float)f.ReadByte() * NORMAL_MULT;
                        nx       = (float)(Math.Cos(lat) * Math.Sin(lng));
                        ny       = (float)(Math.Sin(lat) * Math.Sin(lng));
                        nz       = (float)(Math.Cos(lng));
                        norms[i] = new Vec3(-ny, nz, nx);
                    }

                    // Сохранение кадра
                    MorphMeshComponent.MorphFrame frame = new MorphMeshComponent.MorphFrame();
                    frame.Time         = frameIndex;
                    frame.Vertices     = verts;
                    frame.Normals      = norms;
                    frames[frameIndex] = frame;
                }

                // Поверхность
                MorphMeshComponent surface = new MorphMeshComponent();
                surface.Frames            = frames;
                surface.TexCoords         = texCoords;
                surface.Indices           = indices;
                entry.Surfaces[surfIndex] = surface;
            }

            return(entry);
        }