//�Public�Methods�(1) /// <summary> /// Copy data to other NSBMD material /// </summary> /// <param name="other">Other NSBMD material.</param> public void CopyTo(NsbmdMaterial other) { other.texname = texname; other.texoffset = texoffset; other.texsize = texsize; other.format = format; other.color0 = color0; other.width = width; other.height = height; other.texdata = texdata; other.spdata = spdata; }
//�Public�Methods�(1) /// <summary> /// Copy data to other NSBMD material /// </summary> /// <param name="other">Other NSBMD material.</param> public NsbmdMaterial CopyTo(NsbmdMaterial other1) { NsbmdMaterial other = other1; other.texname = texname; other.texoffset = texoffset; other.texsize = texsize; other.format = format; other.color0 = color0; other.width = width; other.height = height; other.texdata = texdata; other.spdata = spdata; other.MaterialName = MaterialName; return other; }
//�Public�Methods�(1)� /// <summary> /// Copy data to other NSBMD material /// </summary> /// <param name="other">Other NSBMD material.</param> public NsbmdMaterial CopyTo(NsbmdMaterial other1) { NsbmdMaterial other = other1; other.texname = texname; other.texoffset = texoffset; other.texsize = texsize; other.format = format; other.color0 = color0; other.width = width; other.height = height; other.texdata = texdata; other.spdata = spdata; other.MaterialName = MaterialName; return(other); }
/// <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; }
private MKDS_Course_Editor.Export3DTools.Group Process3DCommandRipper(byte[] polydata, NsbmdMaterial m, int jointID, bool color) { MKDS_Course_Editor.Export3DTools.Group group = new MKDS_Course_Editor.Export3DTools.Group(); Vector3 item = new Vector3(float.NaN, 0f, 0f); System.Drawing.Color white = System.Drawing.Color.White; Vector2 vector2 = new Vector2(float.NaN, 0f); List<Vector3> list = new List<Vector3>(); List<Vector3> list2 = new List<Vector3>(); List<Vector2> list3 = new List<Vector2>(); int num = -1; if (polydata != null) { int index = 0; int length = polydata.Length; int[] numArray = new int[4]; float[] numArray4 = new float[3]; float[] v = numArray4; numArray4 = new float[3]; float[] numArray3 = numArray4; int gCurrentVertex = NsbmdGlRenderer.gCurrentVertex; if (this.Model.Objects.Count > 0) { CurrentMatrix = MatrixStack[stackID].Clone(); } else { CurrentMatrix.LoadIdentity(); } if (this.Model.Objects.Count > 1) { } while (index < length) { int num7 = 0; while (num7 < 4) { if (index >= length) { numArray[num7] = 0xff; } else { numArray[num7] = polydata[index]; index++; } num7++; } for (num7 = 0; (num7 < 4) && (index < length); num7++) { int num6; int num8; int num9; int num10; MTX44 mtx; int num11; int num12; int num13; int num26; switch (numArray[num7]) { case 0x70: { index += 12; continue; } case 0x71: { index += 8; continue; } case 0x72: { index += 4; continue; } case 0x60: { index += 4; continue; } case 80: { index += 4; continue; } case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 0x1d: case 30: case 0x1f: case 0x2c: case 0x2d: case 0x2e: case 0x2f: case 0x11: { continue; } case 0x10: { num8 = Utils.Read4BytesAsInt32(polydata, index); index += 4; continue; } case 0x12: { index += 4; continue; } case 0x13: { index += 4; continue; } case 20: { stackID = Utils.Read4BytesAsInt32(polydata, index) & 0x1f; index += 4; MatrixStack[stackID].CopyValuesTo(CurrentMatrix); continue; } case 0x15: { CurrentMatrix.LoadIdentity(); continue; } case 0x16: { num9 = 0; while (num9 < 0x10) { CurrentMatrix[num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f; index += 4; num9++; } continue; } case 0x17: num9 = 0; goto Label_039C; case 0x18: mtx = new MTX44(); mtx.LoadIdentity(); num9 = 0; goto Label_03E8; case 0x19: mtx = new MTX44(); mtx.LoadIdentity(); num9 = 0; goto Label_0466; case 0x1a: mtx = new MTX44(); mtx.LoadIdentity(); num9 = 0; goto Label_04E3; case 0x1b: { num11 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num12 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num13 = Utils.Read4BytesAsInt32(polydata, index); index += 4; CurrentMatrix.Scale((((float)num11) / 4096f) / this.Model.modelScale, (((float)num12) / 4096f) / this.Model.modelScale, (((float)num13) / 4096f) / this.Model.modelScale); continue; } case 0x1c: { num11 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num12 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num13 = Utils.Read4BytesAsInt32(polydata, index); index += 4; CurrentMatrix.translate((((float)sign(num11, 0x20)) / 4096f) / this.Model.modelScale, (((float)sign(num12, 0x20)) / 4096f) / this.Model.modelScale, (((float)sign(num13, 0x20)) / 4096f) / this.Model.modelScale); continue; } case 0x20: { long num14 = Utils.Read4BytesAsInt32(polydata, index); index += 4; if (gOptColoring) { long num15 = num14 & 0x1fL; long num16 = (num14 >> 5) & 0x1fL; long num17 = (num14 >> 10) & 0x1fL; if (color) { white = System.Drawing.Color.FromArgb((int)(((float)m.Alpha) / 31f), (int)(((float)num15) / 31f), (int)(((float)num16) / 31f), (int)(((float)num17) / 31f)); } } continue; } case 0x21: { long num18 = Utils.Read4BytesAsInt32(polydata, index); index += 4; long num19 = num18 & 0x3ffL; if ((num19 & 0x200L) != 0L) { num19 |= -1024L; } long num20 = (num18 >> 10) & 0x3ffL; if ((num20 & 0x200L) != 0L) { num20 |= -1024L; } long num21 = (num18 >> 20) & 0x3ffL; if ((num21 & 0x200L) != 0L) { num21 |= -1024L; } item = new Vector3(((float)num19) / 512f, ((float)num20) / 512f, ((float)num21) / 512f); continue; } case 0x22: { long num22 = Utils.Read4BytesAsInt32(polydata, index); index += 4; long num23 = num22 & 0xffffL; if ((num23 & 0x8000L) != 0L) { num23 |= -65536L; } long num24 = (num22 >> 0x10) & 0xffffL; if ((num24 & 0x8000L) != 0L) { num24 |= -65536L; } vector2 = new Vector2(((m.scaleS / ((float)m.width)) * (((float)num23) / 16f)) / ((float)(m.flipS + 1)), (-(m.scaleT / ((float)m.height)) * (((float)num24) / 16f)) / ((float)(m.flipT + 1))); continue; } case 0x23: { int num25 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num11 = sign(num25 & 0xffff, 0x10); num12 = sign((num25 >> 0x10) & 0xffff, 0x10); num25 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num13 = sign(num25 & 0xffff, 0x10); v[0] = ((float)num11) / 4096f; v[1] = ((float)num12) / 4096f; v[2] = ((float)num13) / 4096f; if (stackID == -1) { goto Label_08E2; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_090F; } case 0x24: num26 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num11 = sign(num26 & 0x3ff, 10); num12 = sign((num26 >> 10) & 0x3ff, 10); num13 = sign((num26 >> 20) & 0x3ff, 10); v[0] = ((float)num11) / 64f; v[1] = ((float)num12) / 64f; v[2] = ((float)num13) / 64f; if (stackID == -1) { goto Label_09E1; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_0A0E; case 0x25: { int num27 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num11 = sign(num27 & 0xffff, 0x10); num12 = sign((num27 >> 0x10) & 0xffff, 0x10); v[0] = ((float)num11) / 4096f; v[1] = ((float)num12) / 4096f; if (stackID == -1) { goto Label_0ABF; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_0AEC; } case 0x26: { int num28 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num11 = sign(num28 & 0xffff, 0x10); num13 = sign((num28 >> 0x10) & 0xffff, 0x10); v[0] = ((float)num11) / 4096f; v[2] = ((float)num13) / 4096f; if (stackID == -1) { goto Label_0B9D; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_0BCA; } case 0x27: { int num29 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num12 = sign(num29 & 0xffff, 0x10); num13 = sign((num29 >> 0x10) & 0xffff, 0x10); v[1] = ((float)num12) / 4096f; v[2] = ((float)num13) / 4096f; if (stackID == -1) { goto Label_0C7B; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_0CA8; } case 40: num26 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num11 = sign(num26 & 0x3ff, 10); num12 = sign((num26 >> 10) & 0x3ff, 10); num13 = sign((num26 >> 20) & 0x3ff, 10); v[0] += ((float)num11) / 4096f; v[1] += ((float)num12) / 4096f; v[2] += ((float)num13) / 4096f; if (stackID == -1) { goto Label_0DAA; } numArray3 = CurrentMatrix.MultVector(v); list.Add(new Vector3(numArray3[0], numArray3[1], numArray3[2])); list2.Add(item); list3.Add(vector2); goto Label_0DD7; case 0x29: { num8 = Utils.Read4BytesAsInt32(polydata, index); index += 4; continue; } case 0x2a: { index += 4; continue; } case 0x2b: { index += 4; continue; } case 0x30: { index += 4; continue; } case 0x31: { index += 4; continue; } case 50: { index += 4; continue; } case 0x33: { index += 4; continue; } case 0x34: { index += 0x80; continue; } case 0x40: num6 = Utils.Read4BytesAsInt32(polydata, index); index += 4; num = num6; switch (num6) { case 0: goto Label_0E92; case 1: goto Label_0E97; case 2: goto Label_0E9C; case 3: goto Label_0EA1; } throw new Exception(); case 0x41: switch (num) { case 0: goto Label_0ED1; case 1: goto Label_0EF6; case 2: goto Label_0F1B; case 3: goto Label_0F40; } goto Label_0F67; default: { continue; } } Label_0358: num10 = 0; while (num10 < 3) { CurrentMatrix[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f; index += 4; num9++; } num9++; Label_039C: if (num9 < 4) { goto Label_0358; } continue; Label_03C1: mtx[num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f; index += 4; num9++; Label_03E8: if (num9 < 0x10) { goto Label_03C1; } CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix); continue; Label_0425: num10 = 0; while (num10 < 3) { mtx[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f; index += 4; num9++; } num9++; Label_0466: if (num9 < 4) { goto Label_0425; } CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix); continue; Label_04A2: num10 = 0; while (num10 < 3) { mtx[num10, num9] = ((float)Utils.Read4BytesAsInt32(polydata, index)) / 4096f; index += 4; num9++; } num9++; Label_04E3: if (num9 < 3) { goto Label_04A2; } CurrentMatrix.MultMatrix(mtx).CopyValuesTo(CurrentMatrix); continue; Label_08E2: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_090F: if (this.writevertex) { } continue; Label_09E1: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_0A0E: if (this.writevertex) { } continue; Label_0ABF: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_0AEC: if (this.writevertex) { } continue; Label_0B9D: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_0BCA: if (this.writevertex) { } continue; Label_0C7B: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_0CA8: if (this.writevertex) { } continue; Label_0DAA: list.Add(new Vector3(v[0], v[1], v[2])); list2.Add(item); list3.Add(vector2); Label_0DD7: if (this.writevertex) { } continue; Label_0E92: num6 = 4; continue; Label_0E97: num6 = 7; continue; Label_0E9C: num6 = 5; continue; Label_0EA1: num6 = 8; continue; Label_0ED1: group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.Triangle, list2.ToArray(), list3.ToArray(), list.ToArray())); goto Label_0F67; Label_0EF6: group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.Quad, list2.ToArray(), list3.ToArray(), list.ToArray())); goto Label_0F67; Label_0F1B: group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.TriangleStrip, list2.ToArray(), list3.ToArray(), list.ToArray())); goto Label_0F67; Label_0F40: group.Add(new MKDS_Course_Editor.Export3DTools.Polygon(PolygonType.QuadStrip, list2.ToArray(), list3.ToArray(), list.ToArray())); Label_0F67: list2.Clear(); list.Clear(); list3.Clear(); gCurrentVertex--; if ((gCurrentVertex < 0) && gOptVertexMode) { return group; } } } } return group; }
/// <summary> /// Process polygon 3d commands. /// </summary> /// <param name="polydata">Data of specific polygon.</param> private void Process3DCommand(byte[] polydata, NsbmdMaterial m, int jointID, bool color) { Gl.glMatrixMode(Gl.GL_MODELVIEW); Gl.glLoadIdentity(); HelixToolkit.MaterialHelper.CreateMaterial(new System.Windows.Media.ImageBrush()); md.Add(new HelixToolkit.MeshBuilder()); IList<System.Windows.Media.Media3D.Point3D> poi = new List<System.Windows.Media.Media3D.Point3D>(); IList<System.Windows.Media.Media3D.Vector3D> nor = new List<System.Windows.Media.Media3D.Vector3D>(); IList<System.Windows.Point> tex = new List<System.Windows.Point>(); int typ = -1; if (polydata == null) return; int commandptr = 0; int commandlimit = polydata.Length; int[] command = new int[4]; int cur_vertex, mode, i; float[] vtx_state = { 0.0f, 0.0f, 0.0f }; float[] vtx_trans = { 0.0f, 0.0f, 0.0f }; cur_vertex = gCurrentVertex; // for vertex_mode if (Model.Objects.Count > 0) { CurrentMatrix = MatrixStack[stackID].Clone(); } else { CurrentMatrix.LoadIdentity(); } if (Model.Objects.Count > 1) { //CurrentMatrix.Scale(Model.modelScale, Model.modelScale, Model.modelScale); } while (commandptr < commandlimit) { for (i = 0; i < 4; ++i) { if (commandptr >= commandlimit) command[i] = 0xFF; else { command[i] = polydata[commandptr]; commandptr++; } } for (i = 0; i < 4 && commandptr < commandlimit; i++) { switch (command[i]) { case 0: // No Operation (for padding packed GXFIFO commands) break; case 0x10: { int param = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; switch (param) { case 0: // Gl.glMatrixMode(Gl.GL_PROJECTION_MATRIX); break; case 1: // Gl.glMatrixMode(Gl.GL_MODELVIEW_MATRIX); break; case 2: break; case 3: // Gl.glMatrixMode(Gl.GL_TEXTURE_MATRIX); break; } break; } case 0x11: break; case 0x12: commandptr += 4; break; case 0x13: commandptr += 4; break; case 0x14: /* MTX_RESTORE - Restore Current Matrix from Stack (W) Sets C=[N]. The stack pointer S is not used, and is left unchanged. Parameter Bit0-4: Stack Address (0..30) (31 causes overflow in GXSTAT.15) Parameter Bit5-31: Not used */ stackID = Utils.Read4BytesAsInt32(polydata, commandptr) & 0x1F;// & 0x0000001F; commandptr += 4; MatrixStack[stackID].CopyValuesTo(CurrentMatrix); break; case 0x15: { CurrentMatrix.LoadIdentity(); break; } case 0x16: { for (int j = 0; j < 16; j++) { CurrentMatrix[j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f; commandptr += 4; } break; } case 0x17: { for (int j = 0; j < 4; j++) { for (int k = 0; k < 3; j++) { CurrentMatrix[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f; commandptr += 4; } } break; } case 0x18: { MTX44 f = new MTX44(); f.LoadIdentity(); for (int j = 0; j < 16; j++) { f[j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f; commandptr += 4; } CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix); break; } case 0x19: { MTX44 f = new MTX44(); f.LoadIdentity(); for (int j = 0; j < 4; j++) { for (int k = 0; k < 3; j++) { f[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f; commandptr += 4; } } CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix); break; } case 0x1A: { MTX44 f = new MTX44(); f.LoadIdentity(); for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; j++) { f[k, j] = (float)Utils.Read4BytesAsInt32(polydata, commandptr) / 4096f; commandptr += 4; } } CurrentMatrix.MultMatrix(f).CopyValuesTo(CurrentMatrix); break; } case 0x1b: /* MTX_SCALE - Multiply Current Matrix by Scale Matrix (W) Sets C=M*C. Parameters: 3, m[0..2] (MTX_SCALE doesn't change Vector Matrix) */ { int x, y, z; x = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; y = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; z = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; //CurrentMatrix[0] = (float)sign(x, 32) / SCALE_IV; //CurrentMatrix[5] = (float)sign(y, 32) / SCALE_IV; //CurrentMatrix[10] = (float)sign(z, 32) / SCALE_IV; //CurrentMatrix.SetValues(scale(CurrentMatrix.Floats, x, y, z)); CurrentMatrix.Scale((float)x / SCALE_IV / Model.modelScale, (float)y / SCALE_IV / Model.modelScale, (float)z / SCALE_IV / Model.modelScale); //CurrentMatrix.Scale((float)sign(x, 32) / SCALE_IV, (float)sign(y, 32) / SCALE_IV, (float)sign(z, 32) / SCALE_IV); break; } case 0x1c: /* MTX_TRANS - Mult. Curr. Matrix by Translation Matrix (W) Sets C=M*C. Parameters: 3, m[0..2] (x,y,z position) */ { int x, y, z; x = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; y = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; z = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; CurrentMatrix.translate((float)sign(x, 32) / SCALE_IV / Model.modelScale, (float)sign(y, 32) / SCALE_IV / Model.modelScale, (float)sign(z, 32) / SCALE_IV / Model.modelScale); break; } case 0x20: // Directly Set Vertex Color (W) { Int64 rgb, r, g, b; rgb = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; if (gOptColoring) { r = (rgb >> 0) & 0x1F; g = (rgb >> 5) & 0x1F; b = (rgb >> 10) & 0x1F; if (color) { Gl.glColor4f(((float)r) / 31.0f, ((float)g) / 31.0f, ((float)b) / 31.0f, m.Alpha / 31.0f); } } } break; case 0x21: /* Set Normal Vector (W) 0-9 X-Component of Normal Vector (1bit sign + 9bit fractional part) 10-19 Y-Component of Normal Vector (1bit sign + 9bit fractional part) 20-29 Z-Component of Normal Vector (1bit sign + 9bit fractional part) 30-31 Not used */ { Int64 xyz, x, y, z; xyz = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = (xyz >> 0) & 0x3FF; if ((x & 0x200) != 0) x |= -1024; y = (xyz >> 10) & 0x3FF; if ((y & 0x200) != 0) y |= -1024; z = (xyz >> 20) & 0x3FF; if ((z & 0x200) != 0) z |= -1024; Gl.glNormal3f(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f); if (writevertex) { //normals.Add(new float[] { ((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f }); //mod.Normals.Add(new System.Windows.Media.Media3D.Vector3D(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f)) nor.Add(new System.Windows.Media.Media3D.Vector3D(((float)x) / 512.0f, ((float)y) / 512.0f, ((float)z) / 512.0f)); } break; } case 0x22: /* Set Texture Coordinates (W) Parameter 1, Bit 0-15 S-Coordinate (X-Coordinate in Texture Source) Parameter 1, Bit 16-31 T-Coordinate (Y-Coordinate in Texture Source) Both values are 1bit sign + 11bit integer + 4bit fractional part. A value of 1.0 (=1 SHL 4) equals to one Texel. */ { Int64 st, s, t; st = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; s = (st >> 0) & 0xffff; if ((s & 0x8000) != 0) s |= unchecked((int)0xFFFF0000);//-65536; t = (st >> 16) & 0xffff; if ((t & 0x8000) != 0) t |= unchecked((int)0xFFFF0000);//-65536; Gl.glTexCoord2f(((float)s) / 16.0f, ((float)t) / 16.0f); if (writevertex) { //mod.TextureCoordinates.Add(new System.Windows.Point((float)s/1024f,(float)t/1024f)); tex.Add(new System.Windows.Point(((float)m.scaleS / (float)m.width) * ((float)s / 16f) / (m.flipS + 1), -((float)m.scaleT / (float)m.height) * ((float)t / 16f) / (m.flipT + 1))); } break; } case 0x23: /* VTX_16 - Set Vertex XYZ Coordinates (W) Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part) Parameter 1, Bit 16-31 Y-Coordinate (signed, with 12bit fractional part) Parameter 2, Bit 0-15 Z-Coordinate (signed, with 12bit fractional part) Parameter 2, Bit 16-31 Not used */ { int parameter, x, y, z; parameter = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = sign((parameter >> 0) & 0xFFFF, 16); //if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536; y = sign((parameter >> 16) & 0xFFFF, 16); //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536; parameter = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; z = sign(parameter & 0xFFFF, 16); // if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536; vtx_state[0] = ((float)x) / SCALE_IV; vtx_state[1] = ((float)y) / SCALE_IV; vtx_state[2] = ((float)z) / SCALE_IV; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } if (writevertex) { //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x24: /* VTX_10 - Set Vertex XYZ Coordinates (W) Parameter 1, Bit 0-9 X-Coordinate (signed, with 6bit fractional part) Parameter 1, Bit 10-19 Y-Coordinate (signed, with 6bit fractional part) Parameter 1, Bit 20-29 Z-Coordinate (signed, with 6bit fractional part) Parameter 1, Bit 30-31 Not used */ { int xyz, x, y, z; xyz = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = sign((xyz >> 0) & 0x3FF, 10); // if ((x & 0x200) != 0) x |= unchecked((int)0xFFFFFC00);//-1024; y = sign((xyz >> 10) & 0x3FF, 10); //if ((y & 0x200) != 0) y |= unchecked((int)0xFFFFFC00);//-1024; z = sign((xyz >> 20) & 0x3FF, 10); // if ((z & 0x200) != 0) z |= unchecked((int)0xFFFFFC00);//-1024; vtx_state[0] = (float)x / 64.0f; vtx_state[1] = (float)y / 64.0f; vtx_state[2] = (float)z / 64.0f; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } if (writevertex) { //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x25: /* VTX_XY - Set Vertex XY Coordinates (W) Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part) Parameter 1, Bit 16-31 Y-Coordinate (signed, with 12bit fractional part) */ { int xy, x, y; xy = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = sign((xy >> 0) & 0xFFFF, 16); //if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536; y = sign((xy >> 16) & 0xFFFF, 16); //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536; vtx_state[0] = ((float)x) / SCALE_IV; vtx_state[1] = ((float)y) / SCALE_IV; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } if (writevertex) { //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x26: /* VTX_XZ - Set Vertex XZ Coordinates (W) Parameter 1, Bit 0-15 X-Coordinate (signed, with 12bit fractional part) Parameter 1, Bit 16-31 Z-Coordinate (signed, with 12bit fractional part) */ { int xz, x, z; xz = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = sign((xz >> 0) & 0xFFFF, 16); // if ((x & 0x8000) != 0) x |= unchecked((int)0xFFFF0000);//-65536; z = sign((xz >> 16) & 0xFFFF, 16); // if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536; vtx_state[0] = ((float)x) / SCALE_IV; vtx_state[2] = ((float)z) / SCALE_IV; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } if (writevertex) { // vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x27: /* VTX_YZ - Set Vertex YZ Coordinates (W) Parameter 1, Bit 0-15 Y-Coordinate (signed, with 12bit fractional part) Parameter 1, Bit 16-31 Z-Coordinate (signed, with 12bit fractional part) */ { int yz, y, z; yz = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; y = sign((yz >> 0) & 0xFFFF, 16); //if ((y & 0x8000) != 0) y |= unchecked((int)0xFFFF0000);//-65536; z = sign((yz >> 16) & 0xFFFF, 16); //if ((z & 0x8000) != 0) z |= unchecked((int)0xFFFF0000);//-65536; vtx_state[1] = ((float)y) / SCALE_IV; vtx_state[2] = ((float)z) / SCALE_IV; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } if (writevertex) { //vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x28: /* VTX_DIFF - Set Relative Vertex Coordinates (W) Parameter 1, Bit 0-9 X-Difference (signed, with 9bit fractional part) Parameter 1, Bit 10-19 Y-Difference (signed, with 9bit fractional part) Parameter 1, Bit 20-29 Z-Difference (signed, with 9bit fractional part) Parameter 1, Bit 30-31 Not used */ { int xyz, x, y, z; xyz = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; x = sign((xyz >> 0) & 0x3FF, 10); //if ((x & 0x200) != 0) x |= unchecked((int)0xFFFFFC00);//-1024; y = sign((xyz >> 10) & 0x3FF, 10); //if ((y & 0x200) != 0) y |= unchecked((int)0xFFFFFC00); z = sign((xyz >> 20) & 0x3FF, 10); //if ((z & 0x200) != 0) z |= unchecked((int)0xFFFFFC00); vtx_state[0] += ((float)x) / SCALE_IV; vtx_state[1] += ((float)y) / SCALE_IV; vtx_state[2] += ((float)z) / SCALE_IV; if (stackID != -1) { vtx_trans = CurrentMatrix.MultVector(vtx_state); Gl.glVertex3fv(vtx_trans); if (writevertex) { //vertex.Add(vtx_trans); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_trans[0], vtx_trans[1], vtx_trans[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if (nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity, 0)); } } } else { Gl.glVertex3fv(vtx_state); if (writevertex) { //vertex.Add(vtx_state); //mod.Positions.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); poi.Add(new System.Windows.Media.Media3D.Point3D(vtx_state[0], vtx_state[1], vtx_state[2])); if (poi.Count > tex.Count && tex.Count != 0) { tex.Add(tex[tex.Count - 1]);//new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } else if (tex.Count == 0) { tex.Add(new System.Windows.Point(double.NegativeInfinity, double.PositiveInfinity)); } if (poi.Count > nor.Count && nor.Count != 0) { nor.Add(nor[nor.Count - 1]); } else if(nor.Count == 0) { nor.Add(new System.Windows.Media.Media3D.Vector3D(double.NegativeInfinity, double.PositiveInfinity,0)); } } } if (writevertex) { // vertex_normal.Add((normals.Count == 0 ? -1 : normals.Count)); } break; } case 0x29: { int param = Utils.Read4BytesAsInt32(polydata, commandptr); commandptr += 4; /*int light = (param >> 0) & 0x10; int polygonMode = (param >> 4) & 0x4; switch (polygonMode) { case 0: mode = Gl.GL_MODULATE; break; case 1: mode = Gl.GL_DECAL; break; case 2: mode = Gl.GL_SHADOW_AMBIENT_SGIX; break; case 3: mode = Gl.GL_QUAD_STRIP; break; default: //return ;// FALSE; throw new Exception(); break; }*/ break; } case 0x2A: commandptr += 4; break; case 0x2B: commandptr += 4; break; // lighting commands case 0x30: commandptr += 4; break; case 0x31: commandptr += 4; break; case 0x32: commandptr += 4; break; case 0x33: { commandptr += 4; break; } case 0x34: commandptr += 128; break; case 0x40: // Start of Vertex List (W) { mode = Utils.Read4BytesAsInt32(polydata, commandptr); //mode = mode & 0x3; commandptr += 4; typ = mode; switch (mode) { case 0: mode = Gl.GL_TRIANGLES; break; case 1: mode = Gl.GL_QUADS; break; case 2: mode = Gl.GL_TRIANGLE_STRIP; break; case 3: mode = Gl.GL_QUAD_STRIP; break; default: //return ;// FALSE; throw new Exception(); break; } Gl.glBegin(mode); break; } case 0x41: // End of Vertex List (W) Gl.glEnd(); //mod.TriangleIndices.Add(nr); //mod.Positions.Add(mod.Positions[mod.Positions.Count - 1]); //mod.Positions.Add(mod.Positions[mod.Positions.Count - 1]); //mod.Positions.Add(mod.Positions[mod.Positions.Count - 1]); //mod.Normals.Add(mod.Normals[mod.Normals.Count - 1]); //mod.Normals.Add(mod.Normals[mod.Normals.Count - 1]); //mod.Normals.Add(mod.Normals[mod.Normals.Count - 1]); if (writevertex) { switch (typ) { case 0: { for (int j = 0; j < poi.Count / 3; j++) { //IList<System.Windows.Media.Media3D.Point3D> pol = new List<System.Windows.Media.Media3D.Point3D>(); //pol.Add(poi[j * 3]); //pol.Add(poi[j * 3 + 1]); //pol.Add(poi[j * 3 + 2]); /*IList<System.Windows.Media.Media3D.Vector3D> norm = new List<System.Windows.Media.Media3D.Vector3D>(); if (norm.Count > j + 1) { norm.Add(nor[j]); } IList<System.Windows.Point> text = new List<System.Windows.Point>(); if (tex.Count > j+1) { text.Add(tex[j]); }*/ //if (tex.Count > j + 1) //{ // md[md.Count - 1].AddTriangle(poi[j * 3], poi[j * 3 + 1], poi[j * 3 + 2], tex[j], tex[j], tex[j]); //} //else if (tex.Count > j * 3 + 2) { md[md.Count - 1].AddTriangle(poi[j * 3], poi[j * 3 + 1], poi[j * 3 + 2], tex[j * 3], tex[j * 3 + 1], tex[j * 3 + 2]); } else { md[md.Count - 1].AddTriangle(poi[j * 3], poi[j * 3 + 1], poi[j * 3 + 2]); } } /*for (int j = 0; j < tex.Count; j++) { md[md.Count - 1].TextureCoordinates.Add(tex[j]); } for (int j = 0; j < nor.Count; j++) { md[md.Count - 1].Normals.Add(nor[j]); }*/ /*HelixToolkit.Mesh3D mb = new HelixToolkit.Mesh3D(); for (int j = 0; j < poi.Count; j += 3) { mb.Vertices.Add(poi[j]); mb.Vertices.Add(poi[j+1]); mb.Vertices.Add(poi[j+2]); mb.AddFace(new int[] { j, j + 1, j + 2 }); } HelixToolkit.MeshBuilder b = new HelixToolkit.MeshBuilder(); b.Append(mb.ToMeshGeometry3D()); //b.AddTriangles(poi, nor, tex); md[mo].Append(b);*/ break; } case 1: { for (int j = 0; j < poi.Count / 4; j++) { //IList<System.Windows.Media.Media3D.Point3D> pol = new List<System.Windows.Media.Media3D.Point3D>(); //pol.Add(poi[j * 4]); //pol.Add(poi[j * 4 + 1]); //pol.Add(poi[j * 4 + 2]); //pol.Add(poi[j * 4 + 3]); /*IList<System.Windows.Media.Media3D.Vector3D> norm = new List<System.Windows.Media.Media3D.Vector3D>(); if (norm.Count > j + 1) { norm.Add(nor[j]); } IList<System.Windows.Point> text = new List<System.Windows.Point>(); if (tex.Count > j + 1) { text.Add(tex[j]); } md[md.Count - 1].AddQuads(pol, norm, text);//.AddPolygon(pol);*/ //if (tex.Count > j + 1) //{ // md[md.Count - 1].AddQuad(poi[j * 4], poi[j * 4 + 1], poi[j * 4 + 2], poi[j * 4 + 3], tex[j], tex[j], tex[j], tex[j]); //} //else if (tex.Count > j * 4 + 3) { md[md.Count - 1].AddQuad(poi[j * 4], poi[j * 4 + 1], poi[j * 4 + 2], poi[j * 4 + 3], tex[j * 4], tex[j * 4 + 1], tex[j * 4 + 2], tex[j * 4 + 3]); } else { md[md.Count - 1].AddQuad(poi[j * 4], poi[j * 4 + 1], poi[j * 4 + 2], poi[j * 4 + 3]); } } /*for (int j = 0; j < tex.Count; j++) { md[md.Count - 1].TextureCoordinates.Add(tex[j]); } for (int j = 0; j < nor.Count; j++) { md[md.Count - 1].Normals.Add(nor[j]); }*/ /* HelixToolkit.Mesh3D mb = new HelixToolkit.Mesh3D(); for (int j = 0; j < poi.Count; j += 4) { mb.Vertices.Add(poi[j]); mb.Vertices.Add(poi[j + 1]); mb.Vertices.Add(poi[j + 2]); mb.Vertices.Add(poi[j + 3]); mb.AddFace(new int[] { j, j + 1, j + 2, j+3 }); } HelixToolkit.MeshBuilder b = new HelixToolkit.MeshBuilder(); b.Append(mb.ToMeshGeometry3D()); //b.AddTriangles(poi, nor, tex); md[mo].Append(b);*/ break; } case 2: { while (poi.Count > nor.Count) { nor.Add(nor[nor.Count - 1]); } while (poi.Count > tex.Count) { tex.Add(tex[tex.Count - 1]); } md[md.Count - 1].AddTriangles(poi, nor, tex); //md[mo].AddTriangleStrip(poi, nor, tex); break; } case 3: { while (poi.Count > nor.Count) { nor.Add(nor[nor.Count - 1]); } while (poi.Count > tex.Count) { tex.Add(tex[tex.Count - 1]); } md[md.Count - 1].AddQuads(poi, nor, tex); //md.AddQuads(poi, nor, tex); break; } default: //return ;// FALSE; break; } } nor.Clear(); tex.Clear(); poi.Clear(); //nr++; // for vertex mode, display at maximum certain number of vertex-list // decrease cur_vertex so that when we reach 0, stop rendering any further cur_vertex--; if (cur_vertex < 0 && gOptVertexMode) return; //TRUE; break; case 0x50: commandptr += 4; break; case 0x60: commandptr += 4; break; case 0x70: commandptr += 12; break; case 0x71: commandptr += 8; break; case 0x72: commandptr += 4; break; default: break; //return FALSE; } } } }
/// <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; }