private void ParseLine(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { switch (parts[0]) { case GraphicTypes.Vertex: var v = new Vertex(); v.ParseFromString(parts); VertexList.Add(v); break; case GraphicTypes.VertexNormal: var vn = new VertexNormal(); vn.ParseFromString(parts); NormalList.Add(vn); break; case GraphicTypes.Face: var f = new Face(); f.ParseFromString(parts); FaceList.Add(f); break; case GraphicTypes.TextureVertex: var vt = new TextureVertex(); vt.ParseFromString(parts); TextureList.Add(vt); break; } } }
private void InitializeBuffers() { vertexCount = 6; indexCount = 6; var vertices = new TextureVertex[vertexCount]; foreach (var vertex in vertices) { //set to zero } int[] indices = new int[indexCount]; for (int i = 0; i < indexCount; i++) { indices[i] = i; } var vertexBufferDesc = new BufferDescription() { Usage = ResourceUsage.Dynamic, //or size of constant buffer SizeInBytes = Utilities.SizeOf <TextureVertex>() * vertexCount, BindFlags = BindFlags.VertexBuffer, CpuAccessFlags = CpuAccessFlags.Write, OptionFlags = ResourceOptionFlags.None, StructureByteStride = 0 }; // Create the vertex buffer. vertexBuffer = Buffer.Create(device, vertices, vertexBufferDesc); // Create the index buffer. indexBuffer = Buffer.Create(device, BindFlags.IndexBuffer, indices); }
static GraphicsBufferView CreateVertexBufferView(GraphicsCopyContext copyContext, GraphicsBuffer vertexBuffer, GraphicsBuffer uploadBuffer, float aspectRatio) { var uploadBufferView = uploadBuffer.CreateBufferView <TextureVertex>(3); var vertexBufferSpan = uploadBufferView.Map <TextureVertex>(); { vertexBufferSpan[0] = new TextureVertex { Position = Vector3.Create(0.0f, 0.25f * aspectRatio, 0.0f), UV = Vector2.Create(0.5f, 0.0f) }; vertexBufferSpan[1] = new TextureVertex { Position = Vector3.Create(0.25f, -0.25f * aspectRatio, 0.0f), UV = Vector2.Create(1.0f, 1.0f) }; vertexBufferSpan[2] = new TextureVertex { Position = Vector3.Create(-0.25f, -0.25f * aspectRatio, 0.0f), UV = Vector2.Create(0.0f, 1.0f) }; } uploadBufferView.UnmapAndWrite(); var vertexBufferView = vertexBuffer.CreateBufferView <TextureVertex>(3); copyContext.Copy(vertexBufferView, uploadBufferView); return(vertexBufferView); }
/// <summary> /// Parses and loads a line from an OBJ file. /// Currently only supports V, VT, F and MTLLIB prefixes /// </summary> private void processLine(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { switch (parts[0]) { case "mtllib": Mtl = parts[1]; break; case "v": Vertex v = new Vertex(); v.LoadFromStringArray(parts); VertexList.Add(v); v.Index = VertexList.Count(); break; case "f": Face f = new Face(); f.LoadFromStringArray(parts); FaceList.Add(f); break; case "vt": TextureVertex vt = new TextureVertex(); vt.LoadFromStringArray(parts); TextureList.Add(vt); vt.Index = TextureList.Count(); break; } } }
private void ProcessLine(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { switch (parts[0]) { case "usemtl": UseMtl = parts[1]; break; case "mtllib": Mtl = parts[1]; break; case "v": Vertex v = new Vertex(); v.LoadFromStringArray(parts); VertexList.Add(v); v.Index = VertexList.Count(); break; case "vn": VertexNormal vn = new VertexNormal(); vn.LoadFromStringArray(parts); NormalList.Add(vn); vn.Index = NormalList.Count(); break; case "s": break; case "f": Face f = new Face(); f.LoadFromStringArray(parts); f.UseMtl = UseMtl; FaceList.Add(f); TriangleCount += f.VertexIndexList.Length - 2; break; case "vt": TextureVertex vt = new TextureVertex(); vt.LoadFromStringArray(parts); TextureList.Add(vt); vt.Index = TextureList.Count(); break; default: System.Diagnostics.Debug.WriteLine(line); break; } } }
public int Compare(TextureVertex x, TextureVertex y) { if (x.XAxis == y.XAxis && x.YAxis == y.YAxis) { return(1); } else { return(0); } }
/// <summary> /// Parses and loads a line from an OBJ file. /// Currently only supports V, VT, F and MTLLIB prefixes /// </summary> private void processLine(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { switch (parts[0]) { case "usemtl": UseMtl = parts[1]; break; case "o": _currentObjectName = parts[1]; objects.Add(_currentObjectName); break; case "mtllib": Mtl = parts[1]; break; case "v": Vertex v = new Vertex(); v.LoadFromStringArray(parts); VertexList.Add(v); v.Index = VertexList.Count(); break; case "vn": Normal vn = new Normal(); vn.LoadFromStringArray(parts); NormalList.Add(vn); vn.Index = NormalList.Count(); break; case "f": Face f = new Face(); f.LoadFromStringArray(parts); f.UseMtl = UseMtl; f.objectName = _currentObjectName; FaceList.Add(f); break; case "vt": TextureVertex vt = new TextureVertex(); vt.LoadFromStringArray(parts); TextureList.Add(vt); vt.Index = TextureList.Count(); break; } } }
private static void ProcessTextureVertex(string[] lineParts, Mesh mesh) { if (lineParts.Length < 3) { return; } if (!float.TryParse(lineParts[1], NumberStyles.Float, CultureInfo.InvariantCulture, out float u) || !float.TryParse(lineParts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out float v)) { return; } TextureVertex textureVertex = new TextureVertex(u, v); mesh.TextureVertices.Add(textureVertex); }
public static T[] TextureVertex <T>(Vector3[] positions) where T : struct { Vector2[] textureCoord = GetTextureCoord(); TextureVertex[] vertices = new TextureVertex[positions.Length]; //from this array, make coresponding structure for (int i = 0; i < positions.Length; i++) { TextureVertex a = new TextureVertex(); a.Position = positions[i]; a.Texture = textureCoord[i]; vertices[i] = a; } var y = (T[])Convert.ChangeType(vertices, typeof(T[])); return(y); }
/// <summary> /// Build a TextureVertexDrawable from the text /// </summary> /// <param name="text"></param> /// <param name="color"></param> /// <param name="scale"></param> /// <returns></returns> private TextureVertexDrawable BuildDrawable(string text, Color color, float scale = 1f) { float UnitScale = WorldTextRenderer.Units * scale; int verticesCount = text.Length * 4; TextureVertex[] vertices = new TextureVertex[verticesCount]; float x = 0f; int i = 0; foreach (char l in text) { if (WorldTextRenderer.CharacterMap.TryGetValue(l, out BmFontChar fontChar)) { Vector4F UVPos = this.CharPositionToUV(fontChar.GetVector4I()); float xOffset = fontChar.XOffset * UnitScale; float yOffset = fontChar.YOffset * UnitScale; float xAdvance = fontChar.XAdvance * UnitScale; float width = fontChar.Width * UnitScale; float height = fontChar.Height * UnitScale; vertices[i].Color = color; vertices[i + 1].Color = color; vertices[i + 2].Color = color; vertices[i + 3].Color = color; vertices[i].Position = new Vector3F(x + xOffset, 0f, 0f); vertices[i + 1].Position = new Vector3F(x + xOffset, height, 0f); vertices[i + 2].Position = new Vector3F(x + xOffset + width, height, 0f); vertices[i + 3].Position = new Vector3F(x + xOffset + width, 0f, 0f); vertices[i].Texture = new Vector2F(UVPos.X, UVPos.W); vertices[i + 1].Texture = new Vector2F(UVPos.X, UVPos.Y); vertices[i + 2].Texture = new Vector2F(UVPos.Z, UVPos.Y); vertices[i + 3].Texture = new Vector2F(UVPos.Z, UVPos.W); x += xAdvance; i += 4; } } return(new TextureVertexDrawable(vertices, verticesCount)); }
public SplashScreen(string engineLogoPath, string fmodLogoPath, string gameLogoPath) { var v0 = new TextureVertex(-1, -1, 0, 0, 0); var v1 = new TextureVertex(1, -1, 0, 1, 0); var v2 = new TextureVertex(-1, 1, 0, 0, 1); var v3 = new TextureVertex(1, 1, 0, 1, 1); _shader = new UnlitShader("EngineAssets/Shaders/textured_mesh.vert", "EngineAssets/Shaders/textured_mesh.frag"); _shader.SetInt("texture0", 0); _engineLogo = new StaticTexturedMesh(engineLogoPath, _shader, "position", "textureCoords", true); _engineLogo.AddSquare(v0, v1, v2, v3); _engineLogo.BakeMesh(); _fmodLogo = new StaticTexturedMesh(fmodLogoPath, _shader, "position", "textureCoords", true); _fmodLogo.AddSquare(v0, v1, v2, v3); _fmodLogo.BakeMesh(); _gameLogo = new StaticTexturedMesh(gameLogoPath, _shader, "position", "textureCoords", true); _gameLogo.AddSquare(v0, v1, v2, v3); _gameLogo.BakeMesh(); }
public List <TextureVertex> LookForTextureVertex() { List <TextureVertex> texVerts = new List <TextureVertex>(); string content = LoadFile.FileContent; List <string> textVertexsTab = new List <string>(); content = content.Remove(0, content.IndexOf("vt ")); var lines = content.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { if (line.StartsWith("vt ")) { textVertexsTab.Add(line.Substring(3)); } } foreach (var vert in textVertexsTab) { TextureVertex texVert = new TextureVertex(); var vertTab = vert.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (vertTab.Length == 2) { texVert.XAxis = (float)Convert.ToDouble(vertTab[0], CultureInfo.InvariantCulture); texVert.YAxis = (float)Convert.ToDouble(vertTab[1], CultureInfo.InvariantCulture); } else { throw new NullReferenceException(message: $"Doesn't found x, y TExtureVertex. \n textVertexsTab[this] = {vert}\n"); } texVerts.Add(texVert); //normals.Add(new Normal() { XAxis = 0, YAxis = -1, ZAxis = 0 }); //normals.Add(new Normal() { XAxis = 0, YAxis = 1, ZAxis = 0 }); } waveFront.TexVertexs = texVerts; return(texVerts); }
private void ProcessLine(string line) { var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length <= 0) { return; } switch (parts[0]) { case "v": var vertex = new GeometricVertex(); vertex.ProcessData(parts, _maxValue); GeometricVertices.Add(vertex); break; case "f": var face = new FaceVertex(); face.ProcessData(parts); FaceVertices.Add(face); break; case "vt": var textureVertex = new TextureVertex(); textureVertex.ProcessData(parts); TextureVertices.Add(textureVertex); break; case "vn": var normalVertex = new NormalVertex(); normalVertex.ProcessData(parts); NormalVertices.Add(normalVertex); break; } }
private static void ProcessFace(string[] lineParts, Mesh mesh) { if (lineParts.Length < 4) { return; } List <FaceElement> faceElements = new List <FaceElement>(); for (int i = 1; i < lineParts.Length; i++) { string linePart = lineParts[i]; string[] referenceNumberParts = linePart.Split('/'); if (referenceNumberParts.Length == 3) { Vertex v = GetExistingVertex(referenceNumberParts[0], mesh.GeometricVertices); TextureVertex vt = GetExistingVertex(referenceNumberParts[1], mesh.TextureVertices); Vector vn = GetExistingVertex(referenceNumberParts[2], mesh.VertexNormals); faceElements.Add(new FaceElement(v, vt, vn)); } else if (referenceNumberParts.Length == 1) { Vertex v = GetExistingVertex(referenceNumberParts[0], mesh.GeometricVertices); faceElements.Add(new FaceElement(v, null, null)); } else { return; } } mesh.Faces.Add(new Face(faceElements)); }
/// <summary> /// Parses and loads a line from an OBJ file. /// Currently only supports V, VT, F and MTLLIB prefixes /// </summary> private void processLine2(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); gf CurrentGroup = Objects[Objects.Count - 1].groups[Objects[Objects.Count - 1].groups.Count - 1]; if (parts.Length > 0) { switch (parts[0]) { case "usemtl": UseMtl = parts[1]; break; case "mtllib": Mtl = parts[1]; break; case "v": Vertex v = new Vertex(); v.LoadFromStringArray(parts); VertexList.Add(v); v.Index = VertexList.Count(); //CurrentGroup.vertexList.Add(v); //v.Index = CurrentGroup.vertexList.Count(); break; case "f": Face f = new Face(); f.LoadFromStringArray(parts); f.UseMtl = UseMtl; //FaceList.Add(f); GroupFaces[GroupFaces.Count - 1].faces.Add(f); break; case "vt": TextureVertex vt = new TextureVertex(); vt.LoadFromStringArray(parts); TextureList.Add(vt); vt.Index = TextureList.Count(); break; case "g": if (gVerified) { GroupFaces.Add(new gf()); } else { gVerified = true; } GroupFaces[GroupFaces.Count - 1].name = parts[1]; break; case "o": //objects and groups are usually considered indetical, however objects in T2T are used to represent shapes, while groups are used to represent primitives //when an o is encountered, we create a new o into the object list and set our global o pointer to the newly made o //when we do the import, a group faces is a primitive so we can loop through all o's(shapes) and get all GroupFaces(primitives) //there is always a default group 0, and if the user imports an obj with no groups or objects, we just push them all into object 0 group 0 if (oVerified) { Objects.Add(new obj()); } else { oVerified = true; } Objects[Objects.Count - 1].name = parts[1]; Objects[Objects.Count - 1].groups.Add(GroupFaces[GroupFaces.Count - 1]); break; } } }
/// <summary> /// Writes an OBJ uses vertices and faces contained within the provided boundries. /// Typically used by WriteObjGridTile(...) /// Returns number of vertices written, or 0 if nothing was written. /// </summary> public int WriteObj(string path, Extent boundries) { if (!Directory.Exists(Path.GetDirectoryName(path))) { Directory.CreateDirectory(Path.GetDirectoryName(path)); } if (File.Exists(path)) { File.Delete(path); } // Build the chunk List <Vertex> chunkVertexList; List <Face> chunkFaceList; List <TextureVertex> chunkTextureList; FaceList.ForEach(f => f.RevertVertices()); chunkFaceList = FaceList.Where(v => v.InExtent(boundries, VertexList)).ToList(); // Build a list of vertices indexes needed for these faces List <int> requiredVertices = null; List <int> requiredTextureVertices = null; var tv = Task.Run(() => { requiredVertices = chunkFaceList.SelectMany(f => f.VertexIndexList).Distinct().ToList(); }); var ttv = Task.Run(() => { requiredTextureVertices = chunkFaceList.SelectMany(f => f.TextureVertexIndexList).Distinct().ToList(); }); Task.WaitAll(new Task[] { tv, ttv }); // Abort if we would be writing an empty file if (!requiredVertices.Any()) { return(0); } using (var outStream = File.OpenWrite(path)) using (var writer = new StreamWriter(outStream)) { // Write some header data writer.WriteLine("# Generated by Cuber"); if (!string.IsNullOrEmpty(mtl)) { writer.WriteLine("mtllib " + mtl); } //Write each vertex and update faces Console.WriteLine("Writing vertices."); int newVertexIndex = 0; Parallel.ForEach(requiredVertices, new ParallelOptions { MaxDegreeOfParallelism = NUMCORES }, i => { Vertex moving = VertexList[i - 1]; int newIndex = WriteVertexWithNewIndex(moving, ref newVertexIndex, writer); var facesRequiringUpdate = chunkFaceList.Where(f => f.VertexIndexList.Contains(i)); foreach (var face in facesRequiringUpdate) { face.UpdateVertexIndex(moving.Index, newIndex); } }); //Write each texture vertex and update faces Console.WriteLine("Writing texture vertices."); int newTextureVertexIndex = 0; Parallel.ForEach(requiredTextureVertices, new ParallelOptions { MaxDegreeOfParallelism = NUMCORES }, i => { TextureVertex moving = TextureList[i - 1]; int newIndex = WriteVertexWithNewIndex(moving, ref newTextureVertexIndex, writer); var facesRequiringUpdate = chunkFaceList.Where(f => f.TextureVertexIndexList.Contains(i)); foreach (var face in facesRequiringUpdate) { face.UpdateTextureVertexIndex(moving.Index, newIndex); } }); // Write the faces Console.WriteLine("Writing faces."); chunkFaceList.ForEach(f => writer.WriteLine(f)); } return(requiredVertices.Count()); }
public FaceElement(Vertex v, TextureVertex vt, Vector vn) { V = v; Vt = vt; Vn = vn; }
/// <summary> /// Build a TextureVertexDrawable from the text where it is contained within a region /// </summary> /// <param name="text"></param> /// <param name="textBox"></param> /// <param name="alignment"></param> /// <param name="color"></param> /// <param name="scale"></param> /// <returns></returns> private TextureVertexDrawable BuildDrawable(string text, Vector2F textBox, BmFontAlign alignment, Color color, float scale) { float UnitScale = WorldTextRenderer.Units * scale; int verticesCount = text.Length * 4; TextureVertex[] vertices = new TextureVertex[verticesCount]; List <BmFontCharInfo> charInfo = new List <BmFontCharInfo>(); List <float> lineWidths = new List <float>(); // Textbox edge locations, make its origin the center float textBoxLeft = -textBox.X * 0.5f; float textBoxRight = textBox.X * 0.5f; float textBoxTop = textBox.Y * 0.5f; float textBoxBottom = -textBox.Y * 0.5f; // Keep track of offset positions int vIdx = 0; // Vertex index float x = textBoxLeft; float y = textBoxTop; float lineHeight = WorldTextRenderer.FontFile.Info.Size * UnitScale; float lineWidth = 0f; int lineNumber = 1; int wordNumber = 1; // First we build everything, afterward we reposition vertices according to the BmFontCharinfo and alignment // Should be slightly more efficient as to realign all previous characters on the line as soon as we add a new one foreach (char c in text) { // Supplied new line if (c == '\r' || c == '\n') { x = textBoxLeft; y -= lineHeight; lineWidths.Add(lineWidth); lineWidth = 0f; wordNumber = 1; lineNumber++; continue; } BmFontChar fontChar = WorldTextRenderer.CharacterMap.GetOrDefault(c); if (fontChar == null) { continue; } float xOffset = fontChar.XOffset * UnitScale; float yOffset = fontChar.YOffset * UnitScale; float xAdvance = fontChar.XAdvance * UnitScale; float width = fontChar.Width * UnitScale; float height = fontChar.Height * UnitScale; // Newline supplied or needed if (lineWidth + xAdvance >= textBox.X) { x = textBoxLeft; y -= lineHeight; // Outside of bottom boundary; just stop if (y - yOffset - lineHeight < textBoxBottom) { break; } // If we exceed the textbox and are not on the first word // we move the last word down a line if (wordNumber != 1) { float previousLineWidth = lineWidth; lineWidth = 0f; for (int i = 0; i < charInfo.Count; i++) { // If the previous line ended with a space remove it's width if (charInfo[i].LineNumber == lineNumber && charInfo[i].WordNumber == (wordNumber - 1) && charInfo[i].Char == ' ') { previousLineWidth -= charInfo[i].XAdvance; } if (charInfo[i].LineNumber == lineNumber && charInfo[i].WordNumber == wordNumber) { charInfo[i].LineNumber++; charInfo[i].WordNumber = 1; vertices[charInfo[i].FirstVertexIndex].Position.X = x + charInfo[i].XOffset; vertices[charInfo[i].FirstVertexIndex].Position.Y = y - charInfo[i].Height; vertices[charInfo[i].FirstVertexIndex + 1].Position.X = x + charInfo[i].XOffset; vertices[charInfo[i].FirstVertexIndex + 1].Position.Y = y; vertices[charInfo[i].FirstVertexIndex + 2].Position.X = x + charInfo[i].XOffset + charInfo[i].Width; vertices[charInfo[i].FirstVertexIndex + 2].Position.Y = y; vertices[charInfo[i].FirstVertexIndex + 3].Position.X = x + charInfo[i].XOffset + charInfo[i].Width; vertices[charInfo[i].FirstVertexIndex + 3].Position.Y = y - charInfo[i].Height; x += charInfo[i].XAdvance; lineWidth += charInfo[i].XAdvance; } } lineWidths.Add(previousLineWidth - lineWidth); } else { lineWidths.Add(lineWidth); lineWidth = 0f; } wordNumber = 1; lineNumber++; } // Ignore spaces on a new line if (lineWidth == 0f && c == ' ') { continue; } Vector4F UVPos = this.CharPositionToUV(fontChar.GetVector4I()); vertices[vIdx].Color = color; vertices[vIdx + 1].Color = color; vertices[vIdx + 2].Color = color; vertices[vIdx + 3].Color = color; vertices[vIdx].Position = new Vector3F(x + xOffset, y - height, 0f); vertices[vIdx + 1].Position = new Vector3F(x + xOffset, y, 0f); vertices[vIdx + 2].Position = new Vector3F(x + xOffset + width, y, 0f); vertices[vIdx + 3].Position = new Vector3F(x + xOffset + width, y - height, 0f); vertices[vIdx].Texture = new Vector2F(UVPos.X, UVPos.W); vertices[vIdx + 1].Texture = new Vector2F(UVPos.X, UVPos.Y); vertices[vIdx + 2].Texture = new Vector2F(UVPos.Z, UVPos.Y); vertices[vIdx + 3].Texture = new Vector2F(UVPos.Z, UVPos.W); if (c == ' ') { wordNumber++; } charInfo.Add(new BmFontCharInfo(c, vIdx, xOffset, yOffset, width, height, xAdvance, lineNumber, wordNumber)); if (c == ' ') { wordNumber++; } x += xAdvance; lineWidth += xAdvance; vIdx += 4; } // Bail out early if we have top left alignment if (!alignment.HasFlag(BmFontAlign.Center) && !alignment.HasFlag(BmFontAlign.Right) && !alignment.HasFlag(BmFontAlign.Middle) && !alignment.HasFlag(BmFontAlign.Bottom)) { return(new TextureVertexDrawable(vertices, verticesCount)); } // Add last line, this never creates a new line so we need to manually add it lineWidths.Add(lineWidth); // Lets justify the text! float offsetX = 0; float offsetY = 0; float textHeight = lineWidths.Count * lineHeight; if (alignment.HasFlag(BmFontAlign.Middle)) { offsetY -= (textBox.Y - textHeight) / 2; } if (alignment.HasFlag(BmFontAlign.Bottom)) { offsetY -= textBox.Y - textHeight; } for (int line = 0; line < lineWidths.Count; line++) { lineWidth = lineWidths[line]; if (alignment.HasFlag(BmFontAlign.Center)) { offsetX = (textBox.X - lineWidth) / 2; } if (alignment.HasFlag(BmFontAlign.Right)) { offsetX = textBox.X - lineWidth; } for (int j = 0; j < charInfo.Count; j++) { if (charInfo[j].LineNumber == (line + 1)) { vertices[charInfo[j].FirstVertexIndex].Position.X += offsetX; vertices[charInfo[j].FirstVertexIndex].Position.Y += offsetY; vertices[charInfo[j].FirstVertexIndex + 1].Position.X += offsetX; vertices[charInfo[j].FirstVertexIndex + 1].Position.Y += offsetY; vertices[charInfo[j].FirstVertexIndex + 2].Position.X += offsetX; vertices[charInfo[j].FirstVertexIndex + 2].Position.Y += offsetY; vertices[charInfo[j].FirstVertexIndex + 3].Position.X += offsetX; vertices[charInfo[j].FirstVertexIndex + 3].Position.Y += offsetY; } } } return(new TextureVertexDrawable(vertices, verticesCount)); }
/// <summary> /// Writes out the OpenCTM format for the chunk /// /// According to http://openctm.sourceforge.net/media/FormatSpecification.pdf /// </summary> /// <param name="path">path of file to create</param> /// <param name="chunkFaceList">list of faces associated with this chunk</param> /// <param name="tile">texture tile information (used to associated with specific texture file)</param> private void WriteOpenCtmFormattedFile(string path, List <Face> chunkFaceList, Vector2 tile) { // Build a list of vertices indexes needed for these faces List <Tuple <int, int> > uniqueVertexUVPairs = null; var tv = Task.Run(() => { uniqueVertexUVPairs = chunkFaceList.AsParallel().SelectMany(f => f.VertexIndexList.Zip(f.TextureVertexIndexList, (v, uv) => new Tuple <int, int>(v, uv))).Distinct().ToList(); }); Task.WaitAll(new Task[] { tv }); using (var outStream = File.OpenWrite(path)) using (var writer = new BinaryWriter(outStream)) { // Header writer.Write(Encoding.UTF8.GetBytes("OCTM")); writer.Write(5); // Version writer.Write(0x00574152); // Compression (RAW) writer.Write(uniqueVertexUVPairs.Count); // Vertex count writer.Write(chunkFaceList.Count); // Triangle count writer.Write(1); // UV count writer.Write(0); // attribute map count writer.Write(0); // flags WriteOpenCTMString(writer, "Created by Uniscan's Slice tool (legacy name: PyriteCli)"); // comment //Body Dictionary <Tuple <int, int>, int> seenVertexUVPairs = new Dictionary <Tuple <int, int>, int>(); List <int> vertices = new List <int>(uniqueVertexUVPairs.Count); List <int> uvs = new List <int>(uniqueVertexUVPairs.Count); int nextIndex = 0; // Indices writer.Write(0x58444e49); // "INDX" Parallel.ForEach(chunkFaceList, f => { lock (writer) { for (int i = 0; i < 3; i++) { int vertexIndex = f.VertexIndexList[i]; int uvIndex = f.TextureVertexIndexList[i]; Tuple <int, int> key = new Tuple <int, int>(vertexIndex, uvIndex); if (!seenVertexUVPairs.ContainsKey(key)) { // This is a new vertex uv pair seenVertexUVPairs[key] = nextIndex++; vertices.Add(vertexIndex); uvs.Add(uvIndex); } writer.Write(seenVertexUVPairs[key]); } } }); //Vertices writer.Write(0x54524556); vertices.ForEach(vertexIndex => { Vertex vertex = VertexList[vertexIndex - 1]; writer.Write((float)vertex.X); writer.Write((float)vertex.Y); writer.Write((float)vertex.Z); }); //Normals // Not supported -- Skipped // UV Maps writer.Write(0x43584554); WriteOpenCTMString(writer, "Diffuse color"); WriteOpenCTMString(writer, string.Format("{0}_{1}.jpg", tile.X, tile.Y)); uvs.ForEach(uvIndex => { TextureVertex vertex = TextureList[uvIndex - 1]; writer.Write((float)vertex.X); writer.Write((float)vertex.Y); }); } }
private void WriteObjFormattedFile(string path, string mtlOverride, List <Face> chunkFaceList, Vector2 tile, SlicingOptions options, string comment = "") { // Build a list of vertices indexes needed for these faces List <int> requiredVertices = null; List <int> requiredTextureVertices = null; var tv = Task.Run(() => { requiredVertices = chunkFaceList.AsParallel().SelectMany(f => f.VertexIndexList).Distinct().ToList(); }); var ttv = Task.Run(() => { requiredTextureVertices = chunkFaceList.AsParallel().SelectMany(f => f.TextureVertexIndexList).Distinct().ToList(); }); Task.WaitAll(new Task[] { tv, ttv }); using (var outStream = File.OpenWrite(path)) using (var writer = new StreamWriter(outStream)) { // Write some header data writer.WriteLine("# Generated by Uniscan's Slice tool (legacy name: PyriteCli)"); if (!string.IsNullOrEmpty(comment)) { writer.WriteLine("# " + comment); } if (!string.IsNullOrEmpty(mtlOverride)) { writer.WriteLine("mtllib " + mtlOverride); } else if (!string.IsNullOrEmpty(_mtl) && !options.RequiresTextureProcessing()) { writer.WriteLine("mtllib " + _mtl); } else if (options.RequiresTextureProcessing() && options.WriteMtl) { writer.WriteLine("mtllib texture\\{0}_{1}.mtl", tile.X, tile.Y); } // Write each vertex and update faces _verticesRequireReset = true; int newVertexIndex = 0; Parallel.ForEach(requiredVertices, i => { Vertex moving = VertexList[i - 1]; int newIndex = WriteVertexWithNewIndex(moving, ref newVertexIndex, writer); var facesRequiringUpdate = chunkFaceList.Where(f => f.VertexIndexList.Contains(i)); foreach (var face in facesRequiringUpdate) { face.UpdateVertexIndex(moving.Index, newIndex); } }); // Write each texture vertex and update faces int newTextureVertexIndex = 0; Parallel.ForEach(requiredTextureVertices, i => { TextureVertex moving = TextureList[i - 1]; int newIndex = WriteVertexWithNewIndex(moving, ref newTextureVertexIndex, writer); var facesRequiringUpdate = chunkFaceList.Where(f => f.TextureVertexIndexList.Contains(i)); foreach (var face in facesRequiringUpdate) { face.UpdateTextureVertexIndex(moving.Index, newIndex); } }); // Write the faces chunkFaceList.ForEach(f => writer.WriteLine(f)); } }
/// <summary> /// Parses and loads a line from an OBJ file. /// Currently only supports V, VT, F and MTLLIB prefixes /// </summary> private void processLine(string line) { string[] parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length > 0) { switch (parts[0]) { case "usemtl": UseMtl = parts[1]; if (CurrentGroup == null) { GroupFaces.Add(new gf()); CurrentGroup = GroupFaces[GroupFaces.Count - 1]; CurrentGroup.name = parts[1]; CurrentObject.groups.Add(CurrentGroup); } CurrentGroup.materialName = UseMtl; break; case "mtllib": Mtl = parts[1]; if (Mtl.IndexOf("\\") == -1) { Mtl = Path.GetDirectoryName(ObjPath) + "\\" + Mtl; } break; case "o": //check if we dont already have an active object, aka we arent on the first one if (oVerified) { Objects.Add(new obj()); } else { oVerified = true; } //set global to updated object CurrentObject = Objects[Objects.Count() - 1]; CurrentObject.name = parts[1]; //now any new v, vt, f or g will be added into this object break; case "v": Vertex v = new Vertex(); v.LoadFromStringArray(parts); //VertexList.Add(v); //v.Index = VertexList.Count(); //because we are now doing it my way, we only add to the current object CurrentObject.vertexList.Add(v); break; case "vt": TextureVertex vt = new TextureVertex(); vt.LoadFromStringArray(parts); CurrentObject.textureList.Add(vt); break; case "g": if (gVerified) { GroupFaces.Add(new gf()); } else { gVerified = true; } CurrentGroup = GroupFaces[GroupFaces.Count - 1]; CurrentGroup.name = parts[1]; CurrentObject.groups.Add(CurrentGroup); break; case "f": Face f = new Face(); f.LoadFromStringArray(parts); f.UseMtl = UseMtl; //FaceList.Add(f); CurrentGroup.faces.Add(f); break; } } }
public static bool Init() { if (WasInit) { return(true); } Vertices = new TextureVertex[4]; //Bottom Left Vertices[0] = new TextureVertex() { Position = new Vector3(-0.5f, -0.5f, 0.0f), TexCoord = new Vector2(0.0f, 0.0f) }; //Top Left Vertices[1] = new TextureVertex() { Position = new Vector3(-0.5f, 0.5f, 0.0f), TexCoord = new Vector2(0.0f, 1.0f) }; //Bottom Right Vertices[2] = new TextureVertex() { Position = new Vector3(0.5f, -0.5f, 0.0f), TexCoord = new Vector2(1.0f, 0.0f) }; //Top Right Vertices[3] = new TextureVertex() { Position = new Vector3(0.5f, 0.5f, 0.0f), TexCoord = new Vector2(1.0f, 1.0f) }; ProgramID = Scene.LoadProgramFromStrings(vsSource, fsSource); if (ProgramID == -1) { Logger.LogError("Error loading Texture Preview Shader Program.\n"); return(false); } AttribPosition = GL.GetAttribLocation(ProgramID, "Position"); AttribTexCoord = GL.GetAttribLocation(ProgramID, "TexCoord"); UniformMatrix = GL.GetUniformLocation(ProgramID, "Matrix"); UniformTextureSize = GL.GetUniformLocation(ProgramID, "Size"); UniformTexture = GL.GetUniformLocation(ProgramID, "Texture"); if (AttribPosition == -1 || AttribTexCoord == -1 || UniformMatrix == -1 || UniformTextureSize == -1 || UniformTexture == -1) { Logger.LogError("Error geting Texture Preview Shader Attribute/Uniform Locations\n"); Logger.LogError(string.Format("\tPosition: {0}, TexCoord: {1}, Matrix: {2}, Size: {3}, Texture: {4}\n", AttribPosition, AttribTexCoord, UniformMatrix, UniformTextureSize, UniformTexture)); return(false); } ArrayID = GL.GenVertexArray(); GL.BindVertexArray(ArrayID); BufferID = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, BufferID); Type vType = Vertices[0].GetType(); int vSize = Marshal.SizeOf(vType); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vSize * VertexCount), Vertices, BufferUsageHint.StaticDraw); GL.EnableVertexAttribArray(AttribPosition); GL.VertexAttribPointer(AttribPosition, 3, VertexAttribPointerType.Float, false, vSize, Marshal.OffsetOf(vType, "Position")); GL.EnableVertexAttribArray(AttribTexCoord); GL.VertexAttribPointer(AttribTexCoord, 2, VertexAttribPointerType.Float, false, vSize, Marshal.OffsetOf(vType, "TexCoord")); GL.BindVertexArray(0); GL.BindBuffer(BufferTarget.ArrayBuffer, 0); WasInit = true; return(true); }