/// <summary>
        /// Make texture for model.
        /// </summary>
        /// <param name="mod">NSBMD Model</param>
        private void MakeTexture(NsbmdModel mod)
        {
            Console.WriteLine("DEBUG: making texture for model '{0}'...", mod.Name);

            for (int i = 0; i < mod.Materials.Count; i++)
            {
                if (mod.Materials[i].format == 0) // format 0 is no texture
                    continue;
                var mat = mod.Materials[i];
                if (mat == null || mat.paldata == null)
                    continue;
                int pixelnum = mat.width*mat.height;

                var image = new RGBA[pixelnum];

                switch (mat.format)
                {
                        // No Texture
                    case 0:
                        //puts( "ERROR: format 0" );
                        continue;
                        break;
                        // A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = mat.texdata[j] & 0x1f;
                            int alpha = (mat.texdata[j] >> 5) & 7;
                            alpha = ((alpha*4) + (alpha/2)) << 3;
                            image[j] = mat.paldata[index];
                            image[j].A = (byte) alpha;
                        }
                        break;
                        // 4-Color Palette Texture
                    case 2:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = mat.texdata[j/4];
                            index = (index >> ((j%4) << 1)) & 3;
                            image[j] = mat.paldata[index];
                        }
                        break;
                        // 16-Color Palette Texture
                    case 3:
                        if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            var matindex = j/2;
                            if (mat.texdata.Length < matindex)
                                continue;
                            int index = mat.texdata[matindex];
                            index = (index >> ((j%2) << 2)) & 0x0f;
                            if (mat.paldata == null)
                                continue;
                            if (index < 0 || index >= mat.paldata.Length)
                                continue;
                            if (j < 0 || j >= pixelnum)
                                continue;
                            image[j] = mat.paldata[index];
                        }
                        break;
                        // 256-Color Palette Texture
                    case 4:
                        if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            image[j] = mat.paldata[mat.texdata[j]];
                        }
                        break;
                        // 4x4-Texel Compressed Texture
                    case 5:
                        convert_4x4texel_b(mat.texdata, mat.width, mat.height, mat.spdata, mat.paldata, image);
                        break;
                        // A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = mat.texdata[j] & 0x7;
                            int alpha = (mat.texdata[j] >> 3) & 0x1f;
                            alpha = ((alpha*4) + (alpha/2)) << 3;
                            image[j] = mat.paldata[index];
                            image[j].A = (byte) alpha;
                        }
                        break;
                        // Direct Color Texture
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            UInt16 p = (ushort) (mat.texdata[j*2] + (mat.texdata[j*2 + 1] << 8));
                            image[j].R = (byte) (((p >> 0) & 0x1f) << 3);
                            image[j].G = (byte) (((p >> 5) & 0x1f) << 3);
                            image[j].B = (byte) (((p >> 10) & 0x1f) << 3);
                            image[j].A = (byte) (((p & 0x8000) != 0) ? 0xff : 0);
                        }
                        break;
                }

                /////////////////////////////////////////////////////
                // The trick to handle texture repetition in OpenGL
                // Flip is not supported in Win32 version of OpenGL
                // We have to manually resize the texture, and apply mirror/flip effect

                if (mat.repeat == 0x07)
                {
                    // repeat in s & t direction, flip in s direction
                    // double the width, add a mirror image along the right edge of the texture (s direction)
                    var newimage = new RGBA[pixelnum*2];

                    int newwidth = mat.width*2;
                    int newwidth_1 = newwidth - 1;
                    for (int y = 0; y < mat.height; y++)
                    {
                        int tbase = y*mat.width; // base in original texture
                        int newbase = y*newwidth; // base in new texture
                        for (int x = 0; x < mat.width; x++)
                        {
                            var pixel = image[tbase + x];
                            newimage[newbase + x] = pixel;
                            newimage[newbase + newwidth_1 - x] = pixel;
                        }
                    }
                    mat.width = newwidth;
                    image = newimage;
                }
                else if (mat.repeat == 0x0b)
                {
                    // repeat in s & t direction, flip in t direction
                    // double the height, add a mirror image along the bottom edge of the texture (t direction)
                    var newimage = new RGBA[pixelnum*2];

                    int newheight = mat.height*2;
                    int newheight_1 = mat.height - 1;
                    for (int y = 0; y < mat.height; y++)
                    {
                        int tbase = y*mat.width;
                        int newbase = (newheight_1 - y)*mat.width;
                        for (int x = 0; x < mat.width; x++)
                            newimage[newbase + x] = image[tbase + x];
                    }
                    mat.height = newheight;

                    image = newimage;
                }
                else if (mat.repeat == 0x0f)
                {
                    // repeat in s & t direction, flip in s & t direction
                    // double both width and height, add mirror images along both right and bottom edges
                    var newimage = new RGBA[pixelnum*4];

                    int newwidth = mat.width*2;
                    int newwidth_1 = newwidth - 1;
                    int newheight = mat.height*2;
                    int newheight_1 = newheight - 1;
                    for (int y = 0; y < mat.height; y++)
                    {
                        int tbase = y*mat.width; // base in original texture
                        int topbase = y*newwidth; // top base in new texture
                        int bottombase = (newheight_1 - y)*newwidth; // bottom base in new texture
                        for (int x = 0; x < mat.width; x++)
                        {
                            var pixel = image[tbase + x];
                            newimage[topbase + x] = pixel;
                            newimage[topbase + newwidth_1 - x] = pixel;
                            newimage[bottombase + x] = pixel;
                            newimage[bottombase + newwidth_1 - x] = pixel;
                        }
                    }
                    mat.width = newwidth;
                    mat.height = newheight;

                    image = newimage;
                }

                Console.WriteLine("convert matid = {0}", i);
                Console.WriteLine("\ttex '{0}': {1} [{2},{3}] texsize = {4}", mat.texname, TEXTURE_FORMATS[mat.format], mat.width,
                                  mat.height, mat.texsize);
                Console.WriteLine("\tpal '{0}': pixelnum = {1}, repeat = {2}", mat.palname, pixelnum, mat.repeat);

                var imageBytesList = new List<byte>();
                for (int k = 0; k < image.Length; ++k)
                {
                    imageBytesList.Add(image[k].R);
                    imageBytesList.Add(image[k].G);
                    imageBytesList.Add(image[k].B);
                    imageBytesList.Add(image[k].A);
                }

                var imageBytes = imageBytesList.ToArray();

                Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1);

                Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, mat.width, mat.height, 0, Gl.GL_RGBA,
                                Gl.GL_UNSIGNED_BYTE,
                                imageBytes);

                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);
            }
        }
Exemple #2
0
        /// <summary>
        /// Load materials in stream.
        /// </summary>
        /// <param name="stream">Stream to use.</param>
        /// <returns>Material definitions.</returns>
        public static IEnumerable<NsbmdMaterial> ReadTex0(Stream stream, int blockoffset, out int ptexnum, out int ppalnum, out List<NSBMDTexture> texs, out List<NSBMDPalette> pals)
        {
            EndianBinaryReader reader = new EndianBinaryReader(stream, Endianness.LittleEndian);
            UInt32 blocksize, blockptr, blocklimit;
            int texnum;
            UInt32 texdataoffset;
            int texdatasize;
            UInt32 sptexoffset; // for 4x4 compressed texels only
            int sptexsize; // for 4x4 compressed texels only
            UInt32 spdataoffset; // for 4x4 compressed texels only
            int palnum;
            UInt32 paldefoffset;
            UInt32 paldataoffset;
            int paldatasize;
            NsbmdMaterial[] material = null;
            int i, j;
            texs = new List<NSBMDTexture>();
            pals = new List<NSBMDPalette>();

            blockptr = (uint)(blockoffset + 4); // already read the block ID, so skip 4 bytes
            blocksize = reader.ReadUInt32(); // block size
            blocklimit = (uint)(blocksize + blockoffset);
            Console.WriteLine("DEBUG: blockoffset = {0}, blocksize = {1}", blockoffset, blocksize);

            stream.Skip(4); // skip 4 padding 0s
            texdatasize = reader.ReadUInt16() << 3; // total texture data size div8
            stream.Skip(6); // skip 6 bytes
            texdataoffset = (uint)(reader.ReadUInt32() + blockoffset);

            stream.Skip(4); // skip 4 padding 0s
            sptexsize = reader.ReadUInt16() << 3; // for format 5 4x4-texel, data size div8
            stream.Skip(6); // skip 6 bytesmhm
            sptexoffset = (uint)(reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, data offset
            spdataoffset = (uint)(reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, palette info

            stream.Skip(4); // skip 4 bytes
            paldatasize = reader.ReadUInt16() << 3; // total palette data size div8
            stream.Skip(2); // skip 2 bytes
            paldefoffset = (uint)(reader.ReadUInt32() + blockoffset);
            paldataoffset = (uint)(reader.ReadUInt32() + blockoffset);

            //	printf( "texdataoffset = %08x texdatasize = %08x\n", texdataoffset, texdatasize );
            //	printf( "sptexoffset = %08x sptexsize = %08x spdataoffset = %08x\n", sptexoffset, sptexsize, spdataoffset );
            //	printf( "paldataoffset = %08x paldatasize = %08x\n", paldataoffset, paldatasize );

            ////////////////////////////////////////////////
            // texture definition

            stream.Skip(1); // skip dummy '0'
            texnum = reader.ReadByte(); // no of texture
            blockptr = (uint)stream.Position;
            stream.Seek(paldefoffset, SeekOrigin.Begin);
            stream.Skip(1); // skip dummy '0'
            palnum = reader.ReadByte(); // no of palette
            stream.Seek(blockptr, SeekOrigin.Begin);

            Console.WriteLine("texnum = {0}, palnum = {1}", texnum, palnum);

            // allocate memory for material, great enough to hold all texture and palette
            material = new NsbmdMaterial[(texnum > palnum ? texnum : palnum)];
            for (i = 0; i < material.Length; i++)
                material[i] = new NsbmdMaterial();

            stream.Skip(14 + (texnum * 4)); // go straight to texture info

            for (i = 0; i < texnum; i++)
            {
                UInt32 offset;
                int param;
                int format;
                int width;
                int height;

                var mat = material[i];

                offset = (uint)(reader.ReadUInt16() << 3);
                param = reader.ReadUInt16(); // texture parameter
                stream.Skip(4); // skip 4 bytes

                format = (param >> 10) & 7; // format 0..7, see DSTek
                width = 8 << ((param >> 4) & 7);
                height = 8 << ((param >> 7) & 7);
                mat.color0 = (param >> 13) & 1;

                if (format == 5)
                    mat.texoffset = offset + sptexoffset; // 4x4-Texel Compressed Texture
                else
                    mat.texoffset = offset + texdataoffset;

                mat.format = format;
                mat.width = width;
                mat.height = height;
                NSBMDTexture t = new NSBMDTexture();
                t.format = format;
                t.width = width;
                t.height = height;
                t.color0 = (param >> 13) & 1;
                texs.Add(t);
            }

            ////////////////////////////////////////////
            // copy texture names
            for (i = 0; i < texnum; i++)
            {
                material[i].texname = Utils.ReadNSBMDString(reader);
                reader.BaseStream.Position -= 16;
                texs[i].texname = Utils.ReadNSBMDString(reader);
            }

            ////////////////////////////////////////////////
            // calculate each texture's size
            for (i = 0; i < texnum; i++)
            {
                int[] bpp = { 0, 8, 2, 4, 8, 2, 8, 16 };

                var mat = material[i];
                mat.texsize = (uint)(mat.width * mat.height * bpp[mat.format] / 8);
                Console.WriteLine("tex {0} '{1}': offset = {2} size = {3} [W,H] = [{4}, {5}]",
                                  i, mat.texname, mat.texoffset, mat.texsize, mat.width, mat.height);
                texs[i].texsize = (uint)(mat.width * mat.height * bpp[mat.format] / 8);
            }

            ////////////////////////////////////////////////
            // palette definition
            stream.Seek(paldefoffset + 2, SeekOrigin.Begin); // skip palnum, already read
            stream.Seek(14 + (palnum * 4), SeekOrigin.Current); // go straight to palette info
            for (i = 0; i < palnum; i++)
            {
                uint curOffset = (uint)((reader.ReadUInt16() << 3) + paldataoffset);
                stream.Seek(2, SeekOrigin.Current); // skip 2 bytes
                material[i].paloffset = curOffset;
                NSBMDPalette t = new NSBMDPalette();
                t.paloffset = curOffset;
                pals.Add(t);
            }

            ////////////////////////////////////////////////
            // copy palette names
            for (i = 0; i < palnum; i++)
            {
                var mat = material[i];
                mat.palname = Utils.ReadNSBMDString(reader);
                reader.BaseStream.Position -= 16;
                pals[i].palname = Utils.ReadNSBMDString(reader);
            }

            ////////////////////////////////////////////////
            // calculate each palette's size
            // assume the palettes are stored sequentially
            /*for (i = 0; i < palnum - 1; i++)
            {
                int r;
                var mat = material[i];
                r = i;
                try { while (material[r].paloffset == mat.paloffset) r++; }
                catch { }
                // below is RotA stupid way to calculate the size of palette: next's offset - current's offset
                // it works most of the time
                if (r != palnum)
                {
                    mat.palsize = material[r].paloffset - mat.paloffset;
                    pals[i].palsize = material[r].paloffset - mat.paloffset;
                }
                else
                {
                    mat.palsize = blocklimit - mat.paloffset;
                    pals[i].palsize = blocklimit - mat.paloffset;
                }
                //printf("pal '%s' size = %d\n", mat->palname, mat->palsize);
            }
            material[i].palsize = blocklimit - material[i].paloffset;
            pals[i].palsize = blocklimit - material[i].paloffset;*/
            List<int> offsets = new List<int>();
            for (int k = 0; k < pals.Count; k++)
            {
                if (!offsets.Contains((int)pals[k].paloffset))
                {
                    offsets.Add((int)pals[k].paloffset);
                }
            }
            offsets.Add((int)blocklimit);
            offsets.Sort();
            for (int k = 0; k < pals.Count; k++)
            {
                int pallength;
                int l = -1;
                do
                {
                    l++;
                }
                while (offsets[l] - pals[k].paloffset <= 0);//nsbtx.PalInfo.infoBlock.PalInfo[i + j].Palette_Offset - nsbtx.PalInfo.infoBlock.PalInfo[i].Palette_Offset == 0)
                pallength = offsets[l] - (int)pals[k].paloffset;
                //RGBA[] c_ = pals[k].paldata;
                //List<RGBA> c = new List<RGBA>();
                //c.AddRange(pals[k].paldata.Take(pallength / 2));
                //pals[k].paldata = c.ToArray();
                pals[k].palsize = (uint)pallength;
                material[k].palsize = (uint)pallength;
            }

            ////////////////////////////////////////////////
            // traverse each texture
            for (i = 0; i < texnum; i++)
            {
                var mat = material[i];
                stream.Seek(mat.texoffset, SeekOrigin.Begin);

                ////////////////////////////////////////////////
                // read texture into memory
                byte[] by = reader.ReadBytes((int)mat.texsize);
                mat.texdata = by;
                texs[i].texdata = by;

                Console.WriteLine("DEBUG: texoffset = {0}, texsize = {1}", mat.texoffset, mat.texsize);

                ////////////////////////////////////////////////
                // additional data for format 5 4x4 compressed texels
                if (mat.format == 5)
                {
                    UInt32 r = mat.texsize / 2;//>> 1;
                    stream.Seek(spdataoffset + (mat.texoffset - sptexoffset) / 2, SeekOrigin.Begin);

                    by = reader.ReadBytes((int)r);
                    mat.spdata = by;
                    texs[i].spdata = by;
                    Console.WriteLine("DEBUG: 4x4-texel spdataoffset = {0}, spdatasize = {1}", spdataoffset, r);

                    //spdataoffset += r;
                }
            }

            ////////////////////////////////////////////////
            // traverse each palette
            for (i = 0; i < palnum; i++)
            {
                try
                {
                    NsbmdMaterial mat = material[i];
                    var palentry = mat.palsize >> 1;

                    RGBA[] rgbq = new RGBA[palentry];

                    Console.WriteLine("DEBUG: converting pal '{0}', palentry = {1}", mat.palname, palentry);

                    stream.Seek(mat.paloffset, SeekOrigin.Begin);
                    for (j = 0; j < palentry; j++)
                    {
                        UInt16 p = reader.ReadUInt16();
                        rgbq[j].R = (byte)(((p >> 0) & 0x1f) << 3); // red
                        rgbq[j].G = (byte)(((p >> 5) & 0x1f) << 3); // green
                        rgbq[j].B = (byte)(((p >> 10) & 0x1f) << 3); // blue
                        //rgbq[j].RotA = (p&0x8000) ? 0xff : 0;
                        rgbq[j].A = (p & 0x8000) == 0 ? (byte)0xff : (byte)0;//0xff; // alpha
                    }
                    mat.paldata = rgbq;
                    pals[i].paldata = rgbq;
                }
                catch
                {
                }
            }

            ptexnum = texnum;
            ppalnum = palnum;

            return material;
        }
        /// <summary>
        /// Convert texel (wrapper for type safety issues).
        /// </summary>
        private void convert_4x4texel_b(byte[] tex, int width, int height, byte[] data, RGBA[] pal, RGBA[] rgbaOut)
        {
            var list1 = new List<uint>();
            for (int i = 0; i < (tex.Length + 1)/4; ++i)
                list1.Add(Utils.Read4BytesAsUInt32(tex, i*4));

            var list2 = new List<UInt16>();
            for (int i = 0; i < (data.Length + 1)/2; ++i)
                list2.Add(Utils.Read2BytesAsUInt16(data, i*2));
            var b = convert_4x4texel(list1.ToArray(), width, height, list2.ToArray(), pal, rgbaOut);
        }
        //�Private�Methods�(7)
        /// <summary>
        /// Convert texel.
        /// </summary>
        private bool convert_4x4texel(uint[] tex, int width, int height, UInt16[] data, RGBA[] pal, RGBA[] rgbaOut)
        {
            int w = width/4;
            int h = height/4;

            // traverse 'w x h blocks' of 4x4-texel
            for (int y = 0; y < h; y++)
                for (int x = 0; x < w; x++)
                {
                    int index = y*w + x;
                    UInt32 t = tex[index];
                    UInt16 d = data[index];
                    UInt16 addr = (ushort) (d & 0x3fff);
                    UInt16 mode = (ushort) ((d >> 14) & 3);

                    // traverse every texel in the 4x4 texels
                    for (int r = 0; r < 4; r++)
                        for (int c = 0; c < 4; c++)
                        {
                            int texel = (int) ((t >> ((r*4 + c)*2)) & 3);
                            RGBA pixel = rgbaOut[(y*4 + r)*width + (x*4 + c)];

                            switch (mode)
                            {
                                case 0:
                                    pixel = pal[(addr << 1) + texel];
                                    if (texel == 3) pixel = RGBA.Transparent; // make it transparent, alpha = 0
                                    break;
                                case 2:
                                    pixel = pal[(addr << 1) + texel];
                                    break;
                                case 1:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel.R = (byte) ((pal[(addr << 1)].R + pal[(addr << 1) + 1].R)/2L);
                                            pixel.G = (byte) ((pal[(addr << 1)].G + pal[(addr << 1) + 1].G)/2L);
                                            pixel.B = (byte) ((pal[(addr << 1)].B + pal[(addr << 1) + 1].B)/2L);
                                            pixel.A = 0xff;
                                            break;
                                        case 3:
                                            pixel = RGBA.Transparent; // make it transparent, alpha = 0
                                            break;
                                    }
                                    break;
                                case 3:
                                    switch (texel)
                                    {
                                        case 0:
                                        case 1:
                                            pixel = pal[(addr << 1) + texel];
                                            break;
                                        case 2:
                                            pixel.R = (byte) ((pal[(addr << 1)].R*5L + pal[(addr << 1) + 1].R*3L)/8);
                                            pixel.G = (byte) ((pal[(addr << 1)].G*5L + pal[(addr << 1) + 1].G*3L)/8);
                                            pixel.B = (byte) ((pal[(addr << 1)].B*5L + pal[(addr << 1) + 1].B*3L)/8);
                                            pixel.A = 0xff;
                                            break;
                                        case 3:
                                            pixel.R = (byte) ((pal[(addr << 1)].R*3L + pal[(addr << 1) + 1].R*5L)/8);
                                            pixel.G = (byte) ((pal[(addr << 1)].G*3L + pal[(addr << 1) + 1].G*5L)/8);
                                            pixel.B = (byte) ((pal[(addr << 1)].B*3L + pal[(addr << 1) + 1].B*5L)/8);
                                            pixel.A = 0xff;
                                            break;
                                    }
                                    break;
                            }
                        }
                }
            return true;
        }
Exemple #5
0
 public static RGBA fromColor(System.Drawing.Color c)
 {
     RGBA a = new RGBA();
     a.R = c.R;
     a.G = c.G;
     a.B = c.B;
     a.A = c.A;
     return a;
 }
Exemple #6
0
        /// <summary>
        /// Make texture for model.
        /// </summary>
        /// <param name="mod">NSBMD Model</param>
        private void MakeTexture(int i, NsbmdMaterial m)
        {
            try
            {
                if (m.format == 0) // format 0 is no texture
                {
                    //matt.Add(new System.Windows.Media.ImageBrush());
                    return;
                }
                var mat = m;
                if (mat == null || (mat.paldata == null && mat.format != 7))
                {
                    //matt.Add(new System.Windows.Media.ImageBrush());
                    return;
                }
                int pixelnum = mat.width * mat.height;

                var image = new RGBA[pixelnum];

                switch (mat.format)
                {
                    // No Texture
                    case 0:
                        //puts( "ERROR: format 0" );
                        //mattt.Add(new System.Windows.Media.ImageBrush());
                        return;
                    // A3I5 Translucent Texture (3bit Alpha, 5bit Color Index)
                    case 1:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = mat.texdata[j] & 0x1f;
                            int alpha = (mat.texdata[j] >> 5);// & 7;
                            alpha = ((alpha * 4) + (alpha / 2)) * 8;// << 3;
                            image[j] = mat.paldata[index];
                            image[j].A = (byte)alpha;
                        }

                        break;
                    // 4-Color Palette Texture
                    case 2:
                        if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            uint index = mat.texdata[j / 4];
                            index = (index >> ((j % 4) << 1)) & 3;
                            image[j] = mat.paldata[index];
                        }
                        break;
                    // 16-Color Palette Texture
                    case 3:
                        if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            var matindex = j / 2;
                            if (mat.texdata.Length < matindex)
                                continue;
                            int index = mat.texdata[matindex];
                            index = (index >> ((j % 2) << 2)) & 0x0f;
                            if (mat.paldata == null)
                                continue;
                            if (index < 0 || index >= mat.paldata.Length)
                                continue;
                            if (j < 0 || j >= pixelnum)
                                continue;
                            image[j] = mat.paldata[index];
                        }
                        break;
                    // 256-Color Palette Texture
                    case 4:
                        if (mat.color0 != 0) mat.paldata[0] = RGBA.Transparent; // made palette entry 0 transparent
                        // made palette entry 0 transparent
                        for (int j = 0; j < pixelnum; j++)
                        {
                            image[j] = mat.paldata[mat.texdata[j]];
                        }
                        break;
                    // 4x4-Texel Compressed Texture
                    case 5:
                        convert_4x4texel_b(mat.texdata, mat.width, mat.height, mat.spdata, mat.paldata, image);
                        break;
                    // A5I3 Translucent Texture (5bit Alpha, 3bit Color Index)
                    case 6:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            int index = mat.texdata[j] & 0x7;
                            int alpha = (mat.texdata[j] >> 3);
                            alpha *= 8; //((alpha * 4) + (alpha / 2)) << 3;
                            image[j] = mat.paldata[index];
                            image[j].A = (byte)alpha;
                        }
                        break;
                    // Direct Color Texture
                    case 7:
                        for (int j = 0; j < pixelnum; j++)
                        {
                            //UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
                            //image[j].R = (byte)(((p >> 0) & 0x1f) << 3);
                            //image[j].G = (byte)(((p >> 5) & 0x1f) << 3);
                            //image[j].B = (byte)(((p >> 10) & 0x1f) << 3);
                            //image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
                            image[j] = RGBA.fromColor(Tinke.Convertir.BGR555(mat.texdata[j * 2], mat.texdata[j * 2 + 1]));
                            UInt16 p = (ushort)(mat.texdata[j * 2] + (mat.texdata[j * 2 + 1] << 8));
                            image[j].A = (byte)(((p & 0x8000) != 0) ? 0xff : 0);
                        }
                        break;
                }

                Console.WriteLine("convert matid = {0}", i);
                Console.WriteLine("\ttex '{0}': {1} [{2},{3}] texsize = {4}", mat.texname, TEXTURE_FORMATS[mat.format], mat.width,
                                  mat.height, mat.texsize);
                Console.WriteLine("\tpal '{0}': pixelnum = {1}, repeat = {2}", mat.palname, pixelnum, mat.repeat);

                var imageBytesList = new List<byte>();
                //System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(mat.width, mat.height);
                for (int k = 0; k < image.Length; ++k)
                {
                    //bitmap.SetPixel(k - ((k / (mat.width)) * (mat.width)), k / (mat.width), image[k].ToColor());
                    imageBytesList.Add(image[k].R);
                    imageBytesList.Add(image[k].G);
                    imageBytesList.Add(image[k].B);
                    //if (image[k].A != 0)
                    //{
                    //	imageBytesList.Add((byte)(image[k].A - (255 - (((mat.Alpha + 1) * 8) - 1))));
                    //}
                    //else
                    //{
                        imageBytesList.Add((byte)(image[k].A));
                    //}
                }

                var imageBytes = imageBytesList.ToArray();

                /*System.Windows.Media.ImageBrush br = new System.Windows.Media.ImageBrush(CreateBitmapSourceFromBitmap(bitmap));
                br.Viewbox = new System.Windows.Rect(0, 0, mat.width, mat.height);
                br.ViewboxUnits = System.Windows.Media.BrushMappingMode.Absolute;
                br.Viewport = new System.Windows.Rect(0, 0, 1, 1);
                br.ViewportUnits = System.Windows.Media.BrushMappingMode.Absolute;
                br.Stretch = System.Windows.Media.Stretch.None;
                if (mat.flipS == 1 && mat.flipT == 1)
                {
                    br.TileMode = System.Windows.Media.TileMode.FlipXY;
                }
                else if (mat.flipS == 1)
                {
                    br.TileMode = System.Windows.Media.TileMode.FlipX;
                }
                else if (mat.flipT == 1)
                {
                    br.TileMode = System.Windows.Media.TileMode.FlipY;
                }
                else if (mat.repeatS == 1 || mat.repeatT == 1)
                {
                    br.TileMode = System.Windows.Media.TileMode.Tile;
                }
                else
                {
                    br.TileMode = System.Windows.Media.TileMode.None;
                }
                br.Opacity = (double)(((mat.Alpha + 1) * 8) - 1) / 1.0d;
                matt.Add(br);*/
                //ttt
                Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1 + matstart);
                Gl.glTexImage2D(Gl.GL_TEXTURE_2D, 0, Gl.GL_RGBA, mat.width, mat.height, 0, Gl.GL_RGBA,
                                Gl.GL_UNSIGNED_BYTE,
                                imageBytes);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, Gl.GL_NEAREST);
                Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, Gl.GL_NEAREST);

                if (mat.flipS == 1 && mat.repeatS == 1)
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_MIRRORED_REPEAT);
                }
                else if (mat.repeatS == 1)
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_REPEAT);
                }
                else
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_S, Gl.GL_CLAMP);
                }
                if (mat.flipT == 1 && mat.repeatT == 1)
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_MIRRORED_REPEAT);
                }
                else if (mat.repeatT == 1)
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_REPEAT);
                }
                else
                {
                    Gl.glTexParameterf(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_WRAP_T, Gl.GL_CLAMP);
                }
            }
            catch
            {
                //matt.Add(new System.Windows.Media.ImageBrush());
            }
        }
        /// <summary>
        /// Load materials in stream.
        /// </summary>
        /// <param name="stream">Stream to use.</param>
        /// <returns>Material definitions.</returns>
        public static IEnumerable<NsbmdMaterial> ReadTex0(Stream stream, int blockoffset, out int ptexnum, out int ppalnum)
        {
            BinaryReader reader = new BinaryReader(stream);
            UInt32 blocksize, blockptr, blocklimit;
            int texnum;
            UInt32 texdataoffset;
            int texdatasize;
            UInt32 sptexoffset; // for 4x4 compressed texels only
            int sptexsize; // for 4x4 compressed texels only
            UInt32 spdataoffset; // for 4x4 compressed texels only
            int palnum;
            UInt32 paldefoffset;
            UInt32 paldataoffset;
            int paldatasize;
            NsbmdMaterial[] material = null;
            int i, j;

            blockptr = (uint) (blockoffset + 4); // already read the block ID, so skip 4 bytes
            blocksize = reader.ReadUInt32(); // block size
            blocklimit = (uint) (blocksize + blockoffset);
            Console.WriteLine("DEBUG: blockoffset = {0}, blocksize = {1}", blockoffset, blocksize);

            stream.Skip(4); // skip 4 padding 0s
            texdatasize = reader.ReadUInt16() << 3; // total texture data size div8
            stream.Skip(6); // skip 6 bytes
            texdataoffset = (uint) (reader.ReadUInt32() + blockoffset);

            stream.Skip(4); // skip 4 padding 0s
            sptexsize = reader.ReadUInt16() << 3; // for format 5 4x4-texel, data size div8
            stream.Skip(6); // skip 6 bytesmhm
            sptexoffset = (uint) (reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, data offset
            spdataoffset = (uint) (reader.ReadUInt32() + blockoffset); // for format 5 4x4-texel, palette info

            stream.Skip(4); // skip 4 bytes
            paldatasize = reader.ReadUInt16() << 3; // total palette data size div8
            stream.Skip(2); // skip 2 bytes
            paldefoffset = (uint) (reader.ReadUInt32() + blockoffset);
            paldataoffset = (uint) (reader.ReadUInt32() + blockoffset);

            //	printf( "texdataoffset = %08x texdatasize = %08x\n", texdataoffset, texdatasize );
            //	printf( "sptexoffset = %08x sptexsize = %08x spdataoffset = %08x\n", sptexoffset, sptexsize, spdataoffset );
            //	printf( "paldataoffset = %08x paldatasize = %08x\n", paldataoffset, paldatasize );

            ////////////////////////////////////////////////
            // texture definition

            stream.Skip(1); // skip dummy '0'
            texnum = reader.ReadByte(); // no of texture
            blockptr = (uint) stream.Position;
            stream.Seek(paldefoffset, SeekOrigin.Begin);
            stream.Skip(1); // skip dummy '0'
            palnum = reader.ReadByte(); // no of palette
            stream.Seek(blockptr, SeekOrigin.Begin);

            Console.WriteLine("texnum = {0}, palnum = {1}", texnum, palnum);

            // allocate memory for material, great enough to hold all texture and palette
            material = new NsbmdMaterial[(texnum > palnum ? texnum : palnum)];
            for (i = 0; i < material.Length; ++i)
                material[i] = new NsbmdMaterial();

            stream.Skip(14 + (texnum*4)); // go straight to texture info

            for (i = 0; i < texnum; i++)
            {
                UInt32 offset;
                int param;
                int format;
                int width;
                int height;

                var mat = material[i];

                offset = (uint) (reader.ReadUInt16() << 3);
                param = reader.ReadUInt16(); // texture parameter
                stream.Skip(4); // skip 4 bytes

                format = (param >> 10) & 7; // format 0..7, see DSTek
                width = 8 << ((param >> 4) & 7);
                height = 8 << ((param >> 7) & 7);
                mat.color0 = (param >> 13) & 1;

                if (format == 5)
                    mat.texoffset = offset + sptexoffset; // 4x4-Texel Compressed Texture
                else
                    mat.texoffset = offset + texdataoffset;

                mat.format = format;
                mat.width = width;
                mat.height = height;
            }

            ////////////////////////////////////////////
            // copy texture names
            for (i = 0; i < texnum; i++)
            {
                material[i].texname = Utils.ReadNSBMDString(reader);
            }

            ////////////////////////////////////////////////
            // calculate each texture's size
            for (i = 0; i < texnum; i++)
            {
                int[] bpp = {0, 8, 2, 4, 8, 2, 8, 16};

                var mat = material[i];
                mat.texsize = (uint) (mat.width*mat.height*bpp[mat.format]/8);
                Console.WriteLine("tex {0} '{1}': offset = {2} size = {3} [W,H] = [{4}, {5}]",
                                  i, mat.texname, mat.texoffset, mat.texsize, mat.width, mat.height);
            }

            ////////////////////////////////////////////////
            // palette definition
            stream.Seek(paldefoffset + 2, SeekOrigin.Begin); // skip palnum, already read
            stream.Seek(14 + (palnum*4), SeekOrigin.Current); // go straight to palette info
            for (i = 0; i < palnum; i++)
            {
                uint curOffset = (uint) ((reader.ReadUInt16() << 3) + paldataoffset);
                stream.Seek(2, SeekOrigin.Current); // skip 2 bytes
                material[i].paloffset = curOffset;
            }

            ////////////////////////////////////////////////
            // copy palette names
            for (i = 0; i < palnum; i++)
            {
                var mat = material[i];
                mat.palname = Utils.ReadNSBMDString(reader);
            }

            ////////////////////////////////////////////////
            // calculate each palette's size
            // assume the palettes are stored sequentially
            for (i = 0; i < palnum - 1; i++)
            {
                var mat = material[i];
                var r = i + 1;
                while (material[r].paloffset == mat.paloffset) r++;
                // below is RotA stupid way to calculate the size of palette: next's offset - current's offset
                // it works most of the time
                if (r != palnum)
                    mat.palsize = material[r].paloffset - mat.paloffset;
                else
                    mat.palsize = blocklimit - mat.paloffset;
                //printf("pal '%s' size = %d\n", mat->palname, mat->palsize);
            }
            material[i].palsize = blocklimit - material[i].paloffset;

            ////////////////////////////////////////////////
            // traverse each texture
            for (i = 0; i < texnum; i++)
            {
                var mat = material[i];
                stream.Seek(mat.texoffset, SeekOrigin.Begin);

                ////////////////////////////////////////////////
                // read texture into memory
                mat.texdata = reader.ReadBytes((int) mat.texsize);

                Console.WriteLine("DEBUG: texoffset = {0}, texsize = {1}", mat.texoffset, mat.texsize);

                ////////////////////////////////////////////////
                // additional data for format 5 4x4 compressed texels
                if (true) //(mat.format == 5)
                {
                    UInt32 r = mat.texsize >> 1;
                    stream.Seek(spdataoffset, SeekOrigin.Begin);

                    mat.spdata = reader.ReadBytes((int) r);

                    Console.WriteLine("DEBUG: 4x4-texel spdataoffset = {0}, spdatasize = {1}", spdataoffset, r);

                    spdataoffset += r;
                }
            }

            ////////////////////////////////////////////////
            // traverse each palette
            for (i = 0; i < palnum; i++)
            {
                try
                {
                    NsbmdMaterial mat = material[i];
                    var palentry = mat.palsize >> 1;

                    RGBA[] rgbq = new RGBA[palentry];

                    Console.WriteLine("DEBUG: converting pal '{0}', palentry = {1}", mat.palname, palentry);

                    stream.Seek(mat.paloffset, SeekOrigin.Begin);
                    for (j = 0; j < palentry; j++)
                    {
                        UInt16 p = reader.ReadUInt16();
                        rgbq[j].R = (byte) (((p >> 0) & 0x1f) << 3); // red
                        rgbq[j].G = (byte) (((p >> 5) & 0x1f) << 3); // green
                        rgbq[j].B = (byte) (((p >> 10) & 0x1f) << 3); // blue
                        //rgbq[j].RotA = (p&0x8000) ? 0xff : 0;
                        rgbq[j].A = 0xff; // alpha
                    }
                    mat.paldata = rgbq;
                }
                catch
                {
                }
            }

            ptexnum = texnum;
            ppalnum = palnum;

            return material;
        }