using System; using System.Collections.Generic; using System.Linq; using OpenTK; using System.Windows.Forms; using Toolbox.Library.Rendering; namespace Toolbox.Library { public class STGenericObject : TreeNodeCustom { public STGenericObject() { Checked = true; } public override void OnClick(TreeView treeView) { } //To update buffer data for opengl public virtual void UpdateVertexData() { } public virtual void SaveVertexBuffer() { } public virtual STGenericMaterial GetMaterial() { return new STGenericMaterial(); } public List PolygonGroups = new List(); public bool HasPos; public bool HasNrm; public bool HasUv0; public bool HasUv1; public bool HasUv2; public bool HasWeights; public bool HasIndices; public bool HasBitans; public bool HasTans; public bool HasVertColors; public bool HasVertColors2; public string ObjectName; public int BoneIndex = -1; public int MaterialIndex; public int VertexBufferIndex; public int DisplayLODIndex; public int Offset; private byte vertexSkinCount = 4; public byte VertexSkinCount { get { return vertexSkinCount; } set { vertexSkinCount = value; } } public byte GetMaxSkinInfluenceCount() { return (byte)vertices.Max(t => t.boneIds.Count); } public Vector3 GetOrigin() { Vector3 pos = Vector3.Zero; foreach (Vertex vert in vertices) { } return pos; } public List bones = new List(); public List weightsT = new List(); public List boneList = new List(); public List vertices = new List(); public List lodMeshes = new List(); public class LOD_Mesh { public STPrimitiveType PrimativeType = STPrimitiveType.Triangles; public STIndexFormat IndexFormat = STIndexFormat.UInt16; public uint FirstVertex; public List subMeshes = new List(); public class SubMesh { public uint size; public uint offset; } public void GenerateSubMesh() { subMeshes.Clear(); SubMesh subMesh = new SubMesh(); subMesh.offset = 0; subMesh.size = (uint)faces.Count; subMeshes.Add(subMesh); } public int index = 0; public int strip = 0x40; public int displayFaceSize = 0; public List faces = new List(); public override string ToString() { return "LOD Mesh " + index; } public List getDisplayFace() { if ((strip >> 4) == 4) { displayFaceSize = faces.Count; return faces; } else { List f = new List(); int startDirection = 1; int p = 0; int f1 = faces[p++]; int f2 = faces[p++]; int faceDirection = startDirection; int f3; do { f3 = faces[p++]; if (f3 == 0xFFFF) { f1 = faces[p++]; f2 = faces[p++]; faceDirection = startDirection; } else { faceDirection *= -1; if ((f1 != f2) && (f2 != f3) && (f3 != f1)) { if (faceDirection > 0) { f.Add(f3); f.Add(f2); f.Add(f1); } else { f.Add(f2); f.Add(f3); f.Add(f1); } } f1 = f2; f2 = f3; } } while (p < faces.Count); displayFaceSize = f.Count; return f; } } } public List faces = new List(); #region Methods public static List ConvertTriangleStripsToTriangles(List faces) { List f = new List(); int startDirection = 1; int p = 0; int f1 = faces[p++]; int f2 = faces[p++]; int faceDirection = startDirection; int f3; do { f3 = faces[p++]; if (f3 == 0xFFFF) { f1 = faces[p++]; f2 = faces[p++]; faceDirection = startDirection; } else { faceDirection *= -1; if ((f1 != f2) && (f2 != f3) && (f3 != f1)) { if (faceDirection > 0) { f.Add(f3); f.Add(f2); f.Add(f1); } else { f.Add(f2); f.Add(f3); f.Add(f1); } } f1 = f2; f2 = f3; } } while (p < faces.Count); return f; } public void TransformPosition(Vector3 Position, Vector3 Rotation, Vector3 Scale) { Matrix4 positionMat = Matrix4.CreateTranslation(Position); Matrix4 rotXMat = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(Rotation.X)); Matrix4 rotYMat = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(Rotation.Y)); Matrix4 rotZMat = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(Rotation.Z)); Matrix4 scaleMat = Matrix4.CreateScale(Scale); Matrix4 Transformation = (rotXMat * rotYMat * rotZMat) * positionMat; foreach (Vertex v in vertices) { v.pos = Vector3.TransformPosition(v.pos, scaleMat * Transformation); v.nrm = Vector3.TransformNormal(v.nrm, Transformation); } } public void RemoveDuplicateVertices() { } public void FlipUvsVertical() { foreach (Vertex v in vertices) { v.uv0 = new Vector2(v.uv0.X, 1 - v.uv0.Y); } } public void FlipUvsHorizontal() { foreach (Vertex v in vertices) { v.uv0 = new Vector2(1 - v.uv0.X, v.uv0.Y); } } public void TransformUVs(Vector2 Translate, Vector2 Scale, int Index) { foreach (Vertex v in vertices) { if (Index == 0) v.uv0 = (v.uv0 * Scale) + Translate; else if (Index == 1) v.uv1 = (v.uv1 * Scale) + Translate; else v.uv2 = (v.uv2 * Scale) + Translate; } } public void CalculateTangentBitangent(bool UseUVLayer2) { if (vertices.Count < 3) return; List f = GetFaces(); Vector3[] tanArray = new Vector3[vertices.Count]; Vector3[] bitanArray = new Vector3[vertices.Count]; CalculateTanBitanArrays(f, tanArray, bitanArray, UseUVLayer2); ApplyTanBitanArray(tanArray, bitanArray); } private void ApplyTanBitanArray(Vector3[] tanArray, Vector3[] bitanArray) { if (vertices.Count < 3) return; for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; Vector3 newTan = tanArray[i]; Vector3 newBitan = bitanArray[i]; // The tangent and bitangent should be orthogonal to the normal. // Bitangents are not calculated with a cross product to prevent flipped shading with mirrored normal maps. v.tan = new Vector4(Vector3.Normalize(newTan - v.nrm * Vector3.Dot(v.nrm, newTan)), 1); v.bitan = new Vector4(Vector3.Normalize(newBitan - v.nrm * Vector3.Dot(v.nrm, newBitan)), 1); v.bitan *= -1; } } private void CalculateTanBitanArrays(List faces, Vector3[] tanArray, Vector3[] bitanArray, bool UseUVLayer2) { if (vertices.Count < 3 || faces.Count <= 0) return; for (int i = 0; i < faces.Count; i += 3) { if (faces.Count <= i + 2) continue; Vertex v1 = vertices[faces[i]]; Vertex v2 = vertices[faces[i + 1]]; Vertex v3 = vertices[faces[i + 2]]; float x1 = v2.pos.X - v1.pos.X; float x2 = v3.pos.X - v1.pos.X; float y1 = v2.pos.Y - v1.pos.Y; float y2 = v3.pos.Y - v1.pos.Y; float z1 = v2.pos.Z - v1.pos.Z; float z2 = v3.pos.Z - v1.pos.Z; float s1, s2, t1, t2; if (UseUVLayer2) { s1 = v2.uv1.X - v1.uv1.X; s2 = v3.uv1.X - v1.uv1.X; t1 = v2.uv1.Y - v1.uv1.Y; t2 = v3.uv1.Y - v1.uv1.Y; } else { s1 = v2.uv0.X - v1.uv0.X; s2 = v3.uv0.X - v1.uv0.X; t1 = v2.uv0.Y - v1.uv0.Y; t2 = v3.uv0.Y - v1.uv0.Y; } float div = (s1 * t2 - s2 * t1); float r = 1.0f / div; // Fix +/- infinity from division by 0. if (r == float.PositiveInfinity || r == float.NegativeInfinity) r = 1.0f; float sX = t2 * x1 - t1 * x2; float sY = t2 * y1 - t1 * y2; float sZ = t2 * z1 - t1 * z2; Vector3 s = new Vector3(sX, sY, sZ) * r; float tX = s1 * x2 - s2 * x1; float tY = s1 * y2 - s2 * y1; float tZ = s1 * z2 - s2 * z1; Vector3 t = new Vector3(tX, tY, tZ) * r; // Prevents black tangents or bitangents due to having vertices with the same UV coordinates. float delta = 0.00075f; bool sameU, sameV; if (UseUVLayer2) { sameU = (Math.Abs(v1.uv1.X - v2.uv1.X) < delta) && (Math.Abs(v2.uv1.X - v3.uv1.X) < delta); sameV = (Math.Abs(v1.uv1.Y - v2.uv1.Y) < delta) && (Math.Abs(v2.uv1.Y - v3.uv1.Y) < delta); } else { sameU = (Math.Abs(v1.uv0.X - v2.uv0.X) < delta) && (Math.Abs(v2.uv0.X - v3.uv0.X) < delta); sameV = (Math.Abs(v1.uv0.Y - v2.uv0.Y) < delta) && (Math.Abs(v2.uv0.Y - v3.uv0.Y) < delta); } if (sameU || sameV) { // Let's pick some arbitrary tangent vectors. s = new Vector3(1, 0, 0); t = new Vector3(0, 1, 0); } // Average tangents and bitangents. tanArray[faces[i]] += s; tanArray[faces[i + 1]] += s; tanArray[faces[i + 2]] += s; bitanArray[faces[i]] += t; bitanArray[faces[i + 1]] += t; bitanArray[faces[i + 2]] += t; } } public static void SmoothNormals(List Shapes, int DisplayLODIndex = 0) { if (Shapes.Count == 0) return; //List of duplicate vertices from multiple shapes //We will normalize each vertex with the same normal value to prevent seams List DuplicateVerts = new List(); List NotDuplicateVerts = new List(); for (int s = 0; s < Shapes.Count; s++) { if (Shapes[s].vertices.Count < 3) continue; Vector3[] normals = new Vector3[Shapes[s].vertices.Count]; List f = Shapes[s].GetFaces(); for (int v = 0; v < f.Count; v += 3) { if (f.Count <= v + 2) continue; Vertex v1 = Shapes[s].vertices[f[v]]; Vertex v2 = Shapes[s].vertices[f[v + 1]]; Vertex v3 = Shapes[s].vertices[f[v + 2]]; Vector3 nrm = Shapes[s].CalculateNormal(v1, v2, v3); if (NotDuplicateVerts.Contains(v1.pos)) DuplicateVerts.Add(v1); else NotDuplicateVerts.Add(v1.pos); if (NotDuplicateVerts.Contains(v2.pos)) DuplicateVerts.Add(v2); else NotDuplicateVerts.Add(v2.pos); if (NotDuplicateVerts.Contains(v3.pos)) DuplicateVerts.Add(v3); else NotDuplicateVerts.Add(v3.pos); normals[f[v + 0]] += nrm; normals[f[v + 1]] += nrm; normals[f[v + 2]] += nrm; } for (int n = 0; n < normals.Length; n++) { Shapes[s].vertices[n].nrm = normals[n].Normalized(); } } //Smooth normals normally for (int s = 0; s < Shapes.Count; s++) { // Compare each vertex with all the remaining vertices. This might skip some. for (int i = 0; i < Shapes[s].vertices.Count; i++) { Vertex v = Shapes[s].vertices[i]; for (int j = i + 1; j < Shapes[s].vertices.Count; j++) { Vertex v2 = Shapes[s].vertices[j]; if (v == v2) continue; float dis = (float)Math.Sqrt(Math.Pow(v.pos.X - v2.pos.X, 2) + Math.Pow(v.pos.Y - v2.pos.Y, 2) + Math.Pow(v.pos.Z - v2.pos.Z, 2)); if (dis <= 0f) // Extra smooth { Vector3 nn = ((v2.nrm + v.nrm) / 2).Normalized(); v.nrm = nn; v2.nrm = nn; } } } } //Now do the same but for fixing duplicate vertices for (int s = 0; s < Shapes.Count; s++) { //Smooth duplicate normals for (int i = 0; i < Shapes[s].vertices.Count; i++) { Vertex v = Shapes[s].vertices[i]; for (int j = i + 1; j < DuplicateVerts.Count; j++) { Vertex v2 = DuplicateVerts[j]; if (v.pos == v2.pos) { float dis = (float)Math.Sqrt(Math.Pow(v.pos.X - v2.pos.X, 2) + Math.Pow(v.pos.Y - v2.pos.Y, 2) + Math.Pow(v.pos.Z - v2.pos.Z, 2)); if (dis <= 0f) // Extra smooth { Vector3 nn = ((v2.nrm + v.nrm) / 2).Normalized(); v.nrm = nn; v2.nrm = nn; } } } } } } public void SmoothNormals() { if (vertices.Count < 3) return; Vector3[] normals = new Vector3[vertices.Count]; List f = GetFaces(); for (int i = 0; i < f.Count; i += 3) { if (f.Count <= i + 2) continue; Vertex v1 = vertices[f[i]]; Vertex v2 = vertices[f[i + 1]]; Vertex v3 = vertices[f[i + 2]]; Vector3 nrm = CalculateNormal(v1, v2, v3); normals[f[i + 0]] += nrm; normals[f[i + 1]] += nrm; normals[f[i + 2]] += nrm; } for (int i = 0; i < normals.Length; i++) vertices[i].nrm = normals[i].Normalized(); // Compare each vertex with all the remaining vertices. This might skip some. for (int i = 0; i < vertices.Count; i++) { Vertex v = vertices[i]; for (int j = i + 1; j < vertices.Count; j++) { Vertex v2 = vertices[j]; if (v == v2) continue; float dis = (float)Math.Sqrt(Math.Pow(v.pos.X - v2.pos.X, 2) + Math.Pow(v.pos.Y - v2.pos.Y, 2) + Math.Pow(v.pos.Z - v2.pos.Z, 2)); if (dis <= 0f) // Extra smooth { Vector3 nn = ((v2.nrm + v.nrm) / 2).Normalized(); v.nrm = nn; v2.nrm = nn; } } } } public void InvertNormals() { foreach (Vertex v in vertices) { v.nrm = new Vector3(-1 * v.nrm.X, -1 * v.nrm.Y, -1 * v.nrm.Z); } } public void UVUnwrapPosition() { foreach (Vertex v in vertices) { } } public void CalculateNormals() { if (vertices.Count < 3) return; Vector3[] normals = new Vector3[vertices.Count]; for (int i = 0; i < normals.Length; i++) normals[i] = new Vector3(0, 0, 0); List f = GetFaces(); for (int i = 0; i < f.Count; i += 3) { if (f.Count <= i + 2) continue; Vertex v1 = vertices[f[i]]; Vertex v2 = vertices[f[i + 1]]; Vertex v3 = vertices[f[i + 2]]; Vector3 nrm = CalculateNormal(v1, v2, v3); normals[f[i + 0]] += nrm * (nrm.Length / 2); normals[f[i + 1]] += nrm * (nrm.Length / 2); normals[f[i + 2]] += nrm * (nrm.Length / 2); } for (int i = 0; i < normals.Length; i++) vertices[i].nrm = normals[i].Normalized(); } private List GetFaces() { List f = new List(); if (PolygonGroups.Count > 0) { foreach (var group in PolygonGroups) f.AddRange(group.GetDisplayFace()); } else if (lodMeshes.Count > 0) f = lodMeshes[DisplayLODIndex].getDisplayFace(); return f; } private Vector3 CalculateNormal(Vertex v1, Vertex v2, Vertex v3) { Vector3 U = v2.pos - v1.pos; Vector3 V = v3.pos - v1.pos; // Don't normalize here, so surface area can be calculated. return Vector3.Cross(U, V); } public void SetVertexColor(Vector4 intColor) { // (127, 127, 127, 255) is white. foreach (Vertex v in vertices) { v.col = intColor; } } #endregion } }