//--------------------------------------------------------------- #endregion //--------------------------------------------------------------- //--------------------------------------------------------------- #region Methods //--------------------------------------------------------------- /// <summary> /// Generates a heightmap from a Bitmap. /// </summary> /// <param name="bmp">The bitmap to use.</param> public Mesh Generate(Bitmap bmp) { VertexUnit vertexUnit = new VertexUnit(VertexFormat.PositionTexture, bmp.Width * bmp.Height); PositionStream positionStream = (PositionStream)vertexUnit[typeof(PositionStream)]; TextureStream textureStream = (TextureStream)vertexUnit[typeof(TextureStream)]; BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); byte[] data = new byte[bitmapData.Stride * bitmapData.Height]; System.Runtime.InteropServices.Marshal.Copy(bitmapData.Scan0, data, 0, data.Length); int quadsX = bmp.Width - 1; int quadsY = bmp.Height - 1; Vector3 scale = new Vector3(0.1f, 0.02f, 0.1f); //Vector3 scale = new Vector3(5.0f, 0.1f, 5.0f); for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { int byteOffset = x * 4 + y * bitmapData.Stride; byte b = data[byteOffset]; byte g = data[byteOffset + 1]; byte r = data[byteOffset + 2]; byte a = data[byteOffset + 3]; Vector3 vec = Vector3.Scale(new Vector3(x - quadsX * 0.5f, r, -y + quadsY * 0.5f), scale); positionStream[x + y * bmp.Width] = vec; Vector2 texVec = new Vector2((float)x / quadsX, (float)y / quadsY); textureStream[x + y * bmp.Width] = texVec; } } bmp.UnlockBits(bitmapData); IndexStream indexStream = IndexStream.Create(quadsX * quadsY * 6, (quadsX + 1) * (quadsY + 1)); int offset = 0; for (int y = 0; y < quadsY; y++) { for (int x = 0; x < quadsX; x++) { indexStream[offset] = (x + y * bmp.Width); indexStream[offset + 1] = (x + 1 + y * bmp.Width); indexStream[offset + 2] = (x + (y + 1) * bmp.Width); indexStream[offset + 3] = (x + 1 + y * bmp.Width); indexStream[offset + 4] = (x + 1 + (y + 1) * bmp.Width); indexStream[offset + 5] = (x + (y + 1) * bmp.Width); offset += 6; } } Mesh mesh = new Mesh(); mesh.SubSets.Add(new SubSet(vertexUnit, indexStream)); return(mesh); }
/// <summary> /// Merges two subsets. /// </summary> /// <param name="subSet">Subset to merge with.</param> public void Merge(SubSet subSet) { if (!CanMerge(subSet)) { throw new GraphicsException("Subsets can't be merged!"); } // Merge vertex unit VertexUnit unit = new VertexUnit(VertexUnit.Format, VertexUnit.Size + subSet.VertexUnit.Size); VertexUnit.Copy(VertexUnit, 0, unit, 0, VertexUnit.Size); VertexUnit.Copy(subSet.VertexUnit, 0, unit, VertexUnit.Size, subSet.VertexUnit.Size); VertexUnit.Dispose(); VertexUnit = unit; // Merge index streams IndexStream index = IndexStream.Create(IndexStream.Size + subSet.IndexStream.Size, IndexStream.GetType()); VertexStreams.IndexStream.Copy(IndexStream, 0, index, 0, IndexStream.Size, 0); VertexStreams.IndexStream.Copy(subSet.IndexStream, 0, index, IndexStream.Size, subSet.IndexStream.Size, VertexUnit.Size); IndexStream.Dispose(); IndexStream = index; }
//--------------------------------------------------------------- #endregion //--------------------------------------------------------------- //--------------------------------------------------------------- #region Methods //--------------------------------------------------------------- private void UpdateMetaInfo() { faceNormals = new Vector3[mesh.SubSets.Count][]; backface = new bool[mesh.SubSets.Count][]; edges = new Edge[mesh.SubSets.Count][]; this.shadowVolume = new Mesh(); int maxIndex = 0; for (int iSubSet = 0; iSubSet < mesh.SubSets.Count; iSubSet++) { maxIndex = System.Math.Min(mesh.SubSets[iSubSet].VertexUnit.Size, maxIndex); } indexStream = IndexStream.Create(1024 * 16, maxIndex); for (int iSubSet = 0; iSubSet < mesh.SubSets.Count; iSubSet++) { SubSet subSet = mesh.SubSets[iSubSet]; faceNormals[iSubSet] = subSet.CalcFaceNormals(); backface[iSubSet] = new bool[subSet.PrimitiveCount]; edges[iSubSet] = subSet.CalcEdges(); shadowVolume.SubSets.Add(new SubSet(subSet.VertexUnit, indexStream)); } }
/// <summary> /// Import a mesh from a stream. /// </summary> /// <param name="stream">Stream containing mesh data.</param> public void Import(Stream stream) { Profiler.Instance.Begin("Import binary mesh"); // Header BinaryReader reader = new BinaryReader(stream); if (ReadString(reader) != "mesh" || ReadString(reader) != "v0.3") { throw new NotSupportedException("Can't load mesh, file not supported!"); } // Joints int jointNum = ReadInt(reader); Joint[] joints = new Joint[jointNum]; Matrix4[] jointArray = new Matrix4[jointNum]; Hashtable jointTable = new Hashtable(joints.Length); for (int i = 0; i < joints.Length; i++) { string name = ReadString(reader); string parent = ReadString(reader); reader.Read(matrixBytes, 0, matrixBytes.Length); Matrix4 m = Matrix4.From(matrixBytes); Joint parentJoint = null; if (parent != null && jointTable.Contains(parent)) { parentJoint = (Joint)jointTable[parent]; } joints[i] = new Joint(name, i, parentJoint); jointArray[i] = m; jointTable[name] = joints[i]; } skeleton = new Skeleton(jointArray, joints); // SubSet int subSetNum = ReadInt(reader); for (int i = 0; i < subSetNum; i++) { ArrayList streams = new ArrayList(10); // Header if (ReadString(reader) != "subset") { throw new NotSupportedException("Error on loading subSet!"); } string name = ReadString(reader); string parentJoint = ReadString(reader); int attributeCount = ReadInt(reader); StringDictionary attributes = new StringDictionary(); for (int t = 0; t < attributeCount; t++) { attributes.Add(ReadString(reader), ReadString(reader)); } // IndexStream // Todo Replace ushort.MaxValue with size of vertex unit IndexStream indexStream = IndexStream.Create(ReadInt(reader), ushort.MaxValue); byte[] indexBuffer = new byte[indexStream.Size * 4]; reader.Read(indexBuffer, 0, indexStream.Size * 4); for (int t = 0; t < indexStream.Size; t++) { indexStream[t] = BitConverter.ToInt32(indexBuffer, t * 4); } int vertexSize = ReadInt(reader); PositionStream posStream = new PositionStream(vertexSize); streams.Add(posStream); byte[] vertexBuffer = new byte[vertexSize * 12]; reader.Read(vertexBuffer, 0, vertexSize * 12); for (int t = 0; t < vertexSize; t++) { posStream[t] = Vector3.From(vertexBuffer, 12 * t); } NormalStream normalStream = new NormalStream(vertexSize); streams.Add(normalStream); reader.Read(vertexBuffer, 0, vertexSize * 12); for (int t = 0; t < vertexSize; t++) { normalStream[t] = Vector3.From(vertexBuffer, t * 12); } ColorStream colorStream = new ColorStream(vertexSize); streams.Add(colorStream); reader.Read(vertexBuffer, 0, vertexSize * 12); for (int t = 0; t < vertexSize; t++) { int r = Math.Basic.Clamp((int)(System.BitConverter.ToSingle(vertexBuffer, t * 12) * 255 + 0.5f), 0, 255); int g = Math.Basic.Clamp((int)(System.BitConverter.ToSingle(vertexBuffer, 4 + t * 12) * 255 + 0.5f), 0, 255); int b = Math.Basic.Clamp((int)(System.BitConverter.ToSingle(vertexBuffer, 8 + t * 12) * 255 + 0.5f), 0, 255); colorStream[t] = System.Drawing.Color.FromArgb(r, g, b).ToArgb(); } TextureStream[] textureStreams = new TextureStream[ReadInt(reader)]; for (int t = 0; t < textureStreams.Length; t++) { TextureStream texStream = new TextureStream(vertexSize); streams.Add(texStream); reader.Read(vertexBuffer, 0, vertexSize * 8); for (int j = 0; j < vertexSize; j++) { texStream[j] = Vector2.From(vertexBuffer, j * 8); } textureStreams[t] = texStream; } IBoneIndicesStream boneStream = null; IBoneWeightsStream weightsStream = null; int weightNum = ReadInt(reader); if (weightNum != 0) { if (HardwareSkinning) { boneStream = new BoneIndicesStream(vertexSize); weightsStream = new BoneWeightsStream(vertexSize); } else { boneStream = new SoftwareBoneIndicesStream(vertexSize); weightsStream = new SoftwareBoneWeightsStream(vertexSize); } streams.Add(boneStream); streams.Add(weightsStream); ArrayList[] indicesList = new ArrayList[vertexSize]; ArrayList[] weightsList = new ArrayList[vertexSize]; for (int t = 0; t < vertexSize; t++) { indicesList[t] = new ArrayList(8); weightsList[t] = new ArrayList(8); } byte[] weightBuffer = new byte[weightNum * 12]; reader.Read(weightBuffer, 0, weightNum * 12); for (int t = 0; t < weightNum; t++) { int vertexIndex = BitConverter.ToInt32(weightBuffer, t * 12); int jointIndex = BitConverter.ToInt32(weightBuffer, 4 + t * 12); float weight = BitConverter.ToSingle(weightBuffer, 8 + t * 12); indicesList[vertexIndex].Add((byte)jointIndex); weightsList[vertexIndex].Add(weight); } for (int t = 0; t < vertexSize; t++) { boneStream.SetIndices(t, (byte[])indicesList[t].ToArray(typeof(byte))); weightsStream.SetWeights(t, (float[])weightsList[t].ToArray(typeof(float))); } } VertexUnit vertexUnit = new VertexUnit(streams); Mesh mesh = new Mesh(new SubSet(vertexUnit, indexStream)); if (model == null) { if (skeleton.Joints.Length != 0) { model = new Model(new SkinnedMesh(mesh, skeleton), skeleton); } else { model = new Model(mesh, skeleton); } } else { Joint attachTo = skeleton.RootJoint; if (parentJoint != "") { attachTo = (jointTable[parentJoint] as Joint); } model.AttachModel(new Model(mesh, skeleton), attachTo); } } reader.Close(); Profiler.Instance.End("Import binary mesh"); }
/// <summary> /// loads a quake3 level from a stream /// </summary> /// <param name="stream">stream to load from</param> /// <returns>level as a mesh</returns> public Mesh Load(Stream stream) { Mesh mesh = new Mesh(); this.stream = stream; // get header and check if it is ok QuakeHeader header = (QuakeHeader)RawSerializer.Deserialize(stream, typeof(QuakeHeader)); if (header.ID != 1347633737 || header.Version != 0x2e) { return(null); } // get locations of lumps locations = RawSerializer.DeserializeArray(stream, typeof(LumpLocation), (int)QuakeLumps.LumpNumber); // get lumps IList quakeVertices = LoadLump(QuakeLumps.Vertices, typeof(QuakeVertex)); IList quakeFaces = LoadLump(QuakeLumps.Faces, typeof(QuakeFace)); IList quakeTextures = LoadLump(QuakeLumps.Textures, typeof(QuakeTexture)); IList quakeLightMaps = LoadLump(QuakeLumps.Lightmaps, typeof(QuakeLightMap)); // Load all texture images and put into array IList textures = LoadTextures(quakeTextures); // Load lightMaps, create texture and put into array IList lightMaps = LoadLightMaps(quakeLightMaps); // create list from vertices VertexUnit vertexUnit = new VertexUnit(VertexFormat.PositionTexture2, quakeVertices.Count); PositionStream pos = (PositionStream)vertexUnit[typeof(PositionStream)]; TextureStream texStream = (TextureStream)vertexUnit[typeof(TextureStream)]; TextureStream light = (TextureStream)vertexUnit[typeof(TextureStream), 1]; int i = 0; foreach (QuakeVertex v in quakeVertices) { pos[i] = new Math.Vector3(v.Position[0], v.Position[2], -v.Position[1]); texStream[i] = new Math.Vector2(v.TextureCoord[0], v.TextureCoord[1]); light[i] = new Math.Vector2(v.LightmapCoord[0], v.LightmapCoord[1]); i++; } // presort faces Array.Sort(((Array)quakeFaces)); // create mesh int oldLightMap = ((QuakeFace)quakeFaces[0]).LightmapID; int oldTexture = ((QuakeFace)quakeFaces[0]).TextureID; ArrayList indices = new ArrayList(); for (i = 0; i < quakeFaces.Count; ++i) { QuakeFace qf = (QuakeFace)quakeFaces[i]; if (qf.Type == 1) { if (qf.TextureID != oldTexture || qf.LightmapID != oldLightMap) { mesh.SubSets.Add(new SubSet(vertexUnit, IndexStream.Create(indices, vertexUnit.Size))); Textures texs = new Textures("color", (ITexture)textures[oldTexture]); if (oldLightMap == -1) { texs["lightMap"] = null; } else { texs["lightMap"] = (ITexture)lightMaps[oldLightMap]; } mesh.Textures.Add(texs); indices.Clear(); } // add indices => convert from fan to list for (int j = 2; j < qf.NumOfVerts; j++) { indices.Add(qf.VertexIndex); indices.Add(qf.VertexIndex + j - 1); indices.Add(qf.VertexIndex + j); } oldTexture = qf.TextureID; oldLightMap = qf.LightmapID; } } return(mesh); }