private static void CreateTouchElement(ElementsGroup Group, Vector3 Position, Vector3 Size, int ScreenIndex, int[] SoundIndices, TrainManager.CommandEntry[] CommandEntries) { Vertex t0 = new Vertex(Size.X, Size.Y, -Size.Z); Vertex t1 = new Vertex(Size.X, -Size.Y, -Size.Z); Vertex t2 = new Vertex(-Size.X, -Size.Y, -Size.Z); Vertex t3 = new Vertex(-Size.X, Size.Y, -Size.Z); Vertex t4 = new Vertex(Size.X, Size.Y, Size.Z); Vertex t5 = new Vertex(Size.X, -Size.Y, Size.Z); Vertex t6 = new Vertex(-Size.X, -Size.Y, Size.Z); Vertex t7 = new Vertex(-Size.X, Size.Y, Size.Z); StaticObject Object = new StaticObject(Program.CurrentHost); Object.Mesh.Vertices = new VertexTemplate[] { t0, t1, t2, t3, t4, t5, t6, t7 }; Object.Mesh.Faces = new MeshFace[] { new MeshFace(new int[] { 0, 1, 2, 3 }), new MeshFace(new int[] { 0, 4, 5, 1 }), new MeshFace(new int[] { 0, 3, 7, 4 }), new MeshFace(new int[] { 6, 5, 4, 7 }), new MeshFace(new int[] { 6, 7, 3, 2 }), new MeshFace(new int[] { 6, 2, 1, 5 }) }; Object.Mesh.Materials = new MeshMaterial[1]; Object.Mesh.Materials[0].Flags = 0; Object.Mesh.Materials[0].Color = Color32.White; Object.Mesh.Materials[0].TransparentColor = Color24.Blue; Object.Mesh.Materials[0].DaytimeTexture = null; Object.Mesh.Materials[0].NighttimeTexture = null; Object.Dynamic = true; if (Group.TouchElements == null) { Group.TouchElements = new TouchElement[0]; } int n = Group.TouchElements.Length; Array.Resize(ref Group.TouchElements, n + 1); Group.TouchElements[n] = new TouchElement { Element = new AnimatedObject(Program.CurrentHost), JumpScreenIndex = ScreenIndex, SoundIndices = SoundIndices, ControlIndices = new int[CommandEntries.Length] }; Group.TouchElements[n].Element.States = new [] { new ObjectState() }; Group.TouchElements[n].Element.States[0].Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z); Group.TouchElements[n].Element.States[0].Prototype = Object; Group.TouchElements[n].Element.CurrentState = 0; Group.TouchElements[n].Element.internalObject = new ObjectState { Prototype = Object }; Program.CurrentHost.CreateDynamicObject(ref Group.TouchElements[n].Element.internalObject); int m = Interface.CurrentControls.Length; Array.Resize(ref Interface.CurrentControls, m + CommandEntries.Length); for (int i = 0; i < CommandEntries.Length; i++) { Interface.CurrentControls[m + i].Command = CommandEntries[i].Command; Interface.CurrentControls[m + i].Method = Interface.ControlMethod.Touch; Interface.CurrentControls[m + i].Option = CommandEntries[i].Option; Group.TouchElements[n].ControlIndices[i] = m + i; } }
public static void Freeze(ModelMesh model, FreezeComponents flags) { bool freezePos = flags.HasFlag(FreezeComponents.Position); bool freezeRot = flags.HasFlag(FreezeComponents.Rotation); bool freezeSca = flags.HasFlag(FreezeComponents.Scale); Matrix4D mPosition = Matrix4D.CreateTranslation(model.Parent.Transform.ExtractTranslation()); Matrix4D mRotation = Matrix4D.CreateFromQuaternion(model.Parent.Transform.ExtractRotation()); Matrix4D mScale = Matrix4D.CreateScale(model.Parent.Transform.ExtractScale()); if (freezePos) { model.Parent.Transform = model.Parent.Transform.ClearTranslation(); } if (freezeRot) { model.Parent.Transform = model.Parent.Transform.ClearRotation(); } if (freezeSca) { model.Parent.Transform = model.Parent.Transform.ClearScale(); } foreach (ModelMeshPart meshpart in model.MeshParts) { for (int i = 0; i < meshpart.VertexCount; i++) { if (freezePos) { meshpart.VertexBuffer.ModifyVertexPosition(i, Vector3.TransformVector(meshpart.VertexBuffer.Data[i].Position, mPosition)); } if (freezeRot) { meshpart.VertexBuffer.ModifyVertexPosition(i, Vector3.TransformVector(meshpart.VertexBuffer.Data[i].Position, mRotation)); meshpart.VertexBuffer.ModifyVertexNormal(i, Vector3.TransformNormal(meshpart.VertexBuffer.Data[i].Normal, mRotation)); } if (freezeSca) { meshpart.VertexBuffer.ModifyVertexPosition(i, Vector3.TransformVector(meshpart.VertexBuffer.Data[i].Position, mScale)); } } meshpart.VertexBuffer.Initialise(); } model.BoundingBox.Calculate(model); }
public void Draw() { if (model == null) { model = new Model(); Sphere sphere = new Sphere(0.025f, 7, 7); ModelManipulator.SetVertexColour(sphere, 0, 255, 0, 255); model.AddMesh(sphere); model.SetRenderStyle(RenderStyle.Wireframe); } Matrix4D parentTransform = LinkedBone.CombinedTransform; Transform = Matrix4D.Identity; Vector3 v = parentTransform.ExtractTranslation(); parentTransform.Normalise(); parentTransform.M41 = v.X; parentTransform.M42 = v.Y; parentTransform.M43 = v.Z; Transform *= Matrix4D.CreateFromQuaternion(parentTransform.ExtractRotation()); Transform *= Matrix4D.CreateTranslation(parentTransform.ExtractTranslation()); Matrix4D mS = SceneManager.Current.Transform; Matrix4D mT = Transform; SceneManager.Current.Renderer.PushMatrix(); SceneManager.Current.Renderer.MultMatrix(ref mS); SceneManager.Current.Renderer.MultMatrix(ref mT); model.Draw(); SceneManager.Current.Renderer.PopMatrix(); }
public static void ProcessLevelForCarmageddonMaxDamage() { if (SceneManager.Current.Models.Count == 0) { return; } ModelBoneCollection bones = SceneManager.Current.Models[0].Bones[0].AllChildren(); SceneManager.Current.UpdateProgress("Applying Carmageddon: Max Damage scale"); ModelManipulator.Scale(bones, Matrix4D.CreateScale(6.9f, 6.9f, -6.9f), true); ModelManipulator.FlipFaces(bones, true); SceneManager.Current.UpdateProgress("Fixing material names"); foreach (Material material in SceneManager.Current.Materials) { if (material.Name.Contains(".")) { material.Name = material.Name.Substring(0, material.Name.IndexOf(".")); } material.Name = material.Name.Replace("\\", ""); MATMaterial m = (material.SupportingDocuments["Source"] as MATMaterial); if (!m.HasTexture) { using (Bitmap bmp = new Bitmap(16, 16)) using (Graphics g = Graphics.FromImage(bmp)) { g.FillRectangle(new SolidBrush(Color.FromArgb(m.DiffuseColour[3], m.DiffuseColour[0], m.DiffuseColour[1], m.DiffuseColour[2])), 0, 0, 16, 16); Texture t = new Texture(); t.CreateFromBitmap(bmp, string.Format("{4}_R{0:x2}G{1:x2}B{2:x2}A{3:x2}", m.DiffuseColour[0], m.DiffuseColour[1], m.DiffuseColour[2], m.DiffuseColour[3], material.Name)); material.Texture = t; } } } SceneManager.Current.UpdateProgress("Processing powerups and accessories"); for (int i = bones.Count - 1; i >= 0; i--) { ModelBone bone = bones[i]; if (bone.Name.StartsWith("&")) { if (bone.Name.StartsWith("&£")) { C2Powerup pup = Powerups.LookupID(int.Parse(bone.Name.Substring(2, 2))); Powerup powerup = new Powerup(); if (pup.InMD) { powerup.Name = $"pup_{pup.Name}"; powerup.Tag = pup.Model; } else { powerup.Name = "pup_Credits"; powerup.Tag = pup.Model; } powerup.Transform = bone.CombinedTransform; SceneManager.Current.Entities.Add(powerup); } else { Accessory accessory = new Accessory { Name = $"C2_{bone.Mesh.Name.Substring(3)}" }; SceneManager.Current.Entities.Add(accessory); } SceneManager.Current.Models[0].RemoveBone(bone.Index); } } if (SceneManager.Current.Models[0].SupportingDocuments.ContainsKey("TXT")) { Map map = SceneManager.Current.Models[0].GetSupportingDocument <Map>("TXT"); StartingGrid grid = new StartingGrid { Transform = Matrix4D.CreateTranslation(map.GridPosition.X * 6.9f, map.GridPosition.Y * 6.9f, map.GridPosition.Z * -6.9f) }; SceneManager.Current.Entities.Add(grid); } SceneManager.Current.UpdateProgress("Processing complete!"); SceneManager.Current.SetCoordinateSystem(CoordinateSystem.LeftHanded); SceneManager.Current.Change(ChangeType.Munge, ChangeContext.Model, -1); SceneManager.Current.SetContext("Carmageddon Max Damage", ContextMode.Level); }
public int CreateStaticObject(StaticObject Prototype, Vector3 Position, Transformation BaseTransformation, Transformation AuxTransformation, bool AccurateObjectDisposal, double AccurateObjectDisposalZOffset, double StartingDistance, double EndingDistance, double BlockLength, double TrackPosition, double Brightness) { if (Prototype == null) { return(-1); } float startingDistance = float.MaxValue; float endingDistance = float.MinValue; if (AccurateObjectDisposal) { foreach (VertexTemplate vertex in Prototype.Mesh.Vertices) { Vector3 Coordinates = new Vector3(vertex.Coordinates); Coordinates.Rotate(AuxTransformation); if (Coordinates.Z < startingDistance) { startingDistance = (float)Coordinates.Z; } if (Coordinates.Z > endingDistance) { endingDistance = (float)Coordinates.Z; } } startingDistance += (float)AccurateObjectDisposalZOffset; endingDistance += (float)AccurateObjectDisposalZOffset; } const double minBlockLength = 20.0; if (BlockLength < minBlockLength) { BlockLength *= Math.Ceiling(minBlockLength / BlockLength); } if (AccurateObjectDisposal) { startingDistance += (float)TrackPosition; endingDistance += (float)TrackPosition; double z = BlockLength * Math.Floor(TrackPosition / BlockLength); StartingDistance = Math.Min(z - BlockLength, startingDistance); EndingDistance = Math.Max(z + 2.0 * BlockLength, endingDistance); startingDistance = (float)(BlockLength * Math.Floor(StartingDistance / BlockLength)); endingDistance = (float)(BlockLength * Math.Ceiling(EndingDistance / BlockLength)); } else { startingDistance = (float)StartingDistance; endingDistance = (float)EndingDistance; } StaticObjectStates.Add(new ObjectState { Prototype = Prototype, Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z), //FIXME: This seems to need to be the 'wrong' way around. Need to standardise on Matrices throughout? Rotate = (Matrix4D) new Transformation(AuxTransformation, BaseTransformation), Brightness = Brightness, StartingDistance = startingDistance, EndingDistance = endingDistance }); foreach (MeshFace face in Prototype.Mesh.Faces) { switch (face.Flags & MeshFace.FaceTypeMask) { case MeshFace.FaceTypeTriangles: InfoTotalTriangles++; break; case MeshFace.FaceTypeTriangleStrip: InfoTotalTriangleStrip++; break; case MeshFace.FaceTypeQuads: InfoTotalQuads++; break; case MeshFace.FaceTypeQuadStrip: InfoTotalQuadStrip++; break; case MeshFace.FaceTypePolygon: InfoTotalPolygon++; break; } } return(StaticObjectStates.Count - 1); }
public void Draw() { if (asset == null) { ModelMeshPart sprite = new ModelMeshPart(); sprite.AddVertex(new Vector3(-0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 1)); sprite.AddVertex(new Vector3(-0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 0)); sprite.AddVertex(new Vector3(0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 0)); sprite.AddVertex(new Vector3(0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 1)); sprite.AddVertex(new Vector3(0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 1)); sprite.AddVertex(new Vector3(0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(0, 0)); sprite.AddVertex(new Vector3(-0.25f, 0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 0)); sprite.AddVertex(new Vector3(-0.25f, -0.25f, 0.0f), Vector3.UnitY, new Vector2(1, 1)); sprite.IndexBuffer.Initialise(); sprite.VertexBuffer.Initialise(); sprite.Material = new Material { Name = "Entity.Asset", Texture = SceneManager.Current.Content.Load <Texture, PNGImporter>(IconFilename) }; sprite.PrimitiveType = PrimitiveType.Quads; ModelMesh spritemesh = new ModelMesh(); spritemesh.AddModelMeshPart(sprite); Model spritemodel = new Model(); spritemodel.AddMesh(spritemesh); asset = spritemodel; } if (Linked) { Matrix4D parentTransform = ((ModelBone)Link).CombinedTransform; if (LinkType == LinkType.All) { Transform = parentTransform; } else { Transform = Matrix4D.Identity; Vector3 v = parentTransform.ExtractTranslation(); parentTransform.Normalise(); parentTransform.M41 = v.X; parentTransform.M42 = v.Y; parentTransform.M43 = v.Z; if (LinkType.HasFlag(LinkType.Rotation)) { Transform *= Matrix4D.CreateFromQuaternion(parentTransform.ExtractRotation()); } if (LinkType.HasFlag(LinkType.Scale)) { Transform *= Matrix4D.CreateScale(parentTransform.ExtractScale()); } if (LinkType.HasFlag(LinkType.Position)) { Transform *= Matrix4D.CreateTranslation(parentTransform.ExtractTranslation()); } } } Matrix4D mS = SceneManager.Current.Transform; Matrix4D mT = Transform; SceneManager.Current.Renderer.PushMatrix(); Matrix4D position = Matrix4D.CreateTranslation(mT.ExtractTranslation()); SceneManager.Current.Renderer.MultMatrix(ref mS); SceneManager.Current.Renderer.MultMatrix(ref position); if (Lollipop) { Matrix4D rotation = ViewportManager.Current.Active.Camera.Rotation; Matrix4D scale = Matrix4D.CreateScale(0.1f); SceneManager.Current.Renderer.MultMatrix(ref rotation); SceneManager.Current.Renderer.MultMatrix(ref scale); } SceneManager.Current.Renderer.Enable("Blend"); SceneManager.Current.Renderer.BlendFunc("SrcAlpha", "OneMinusSrcAlpha"); ((Model)asset).Draw(); SceneManager.Current.Renderer.Disable("Blend"); SceneManager.Current.Renderer.PopMatrix(); }
/// <summary> Updates the position and state of the animated object</summary> /// <param name="IsPartOfTrain">Whether this object forms part of a train</param> /// <param name="Train">The train, or a null reference otherwise</param> /// <param name="CarIndex">If this object forms part of a train, the car index it refers to</param> /// <param name="SectionIndex">If this object has been placed via Track.Sig, the index of the section it is attached to</param> /// <param name="TrackPosition"></param> /// <param name="Position"></param> /// <param name="Direction"></param> /// <param name="Up"></param> /// <param name="Side"></param> /// <param name="UpdateFunctions">Whether the functions associated with this object should be re-evaluated</param> /// <param name="Show"></param> /// <param name="TimeElapsed">The time elapsed since this object was last updated</param> /// <param name="EnableDamping">Whether damping is to be applied for this call</param> /// <param name="IsTouch">Whether Animated Object belonging to TouchElement class.</param> /// <param name="Camera"></param> public void Update(bool IsPartOfTrain, AbstractTrain Train, int CarIndex, int SectionIndex, double TrackPosition, Vector3 Position, Vector3 Direction, Vector3 Up, Vector3 Side, bool UpdateFunctions, bool Show, double TimeElapsed, bool EnableDamping, bool IsTouch = false, dynamic Camera = null) { // state change if (StateFunction != null & UpdateFunctions) { double sd = StateFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); int si = (int)System.Math.Round(sd); if (si < 0 | si >= States.Length) { si = -1; } if (CurrentState != si) { ObjectType type = ObjectType.Dynamic; if (Camera != null) { type = ObjectType.Overlay; } Initialize(si, type, Show); CurrentState = si; } } if (CurrentState == -1) { return; //not visible state, so don't bother updating } // translation if (TranslateXFunction != null) { double x = TranslateXFunction.LastResult; if (UpdateFunctions) { x = TranslateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } else if (TranslateXScriptFile != null) { //Translate X Script if (TranslateXAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateXAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateXScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateXScriptFile); TranslateXScriptFile = null; return; } } double x = TranslateXAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateXDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= x; Position += translationVector; } if (TranslateYFunction != null) { double y = TranslateYFunction.LastResult; if (UpdateFunctions) { y = TranslateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } else if (TranslateYScriptFile != null) { //Translate X Script if (TranslateYAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateYAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateYScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateYScriptFile); TranslateYScriptFile = null; return; } } double y = TranslateYAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateYDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= y; Position += translationVector; } if (TranslateZFunction != null) { double z = TranslateZFunction.LastResult; if (UpdateFunctions) { z = TranslateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } else if (TranslateZScriptFile != null) { //Translate X Script if (TranslateZAnimationScript == null) { //Load the script if required try { CSScript.GlobalSettings.TargetFramework = "v4.0"; TranslateZAnimationScript = CSScript.LoadCode(File.ReadAllText(TranslateZScriptFile)) .CreateObject("OpenBVEScript") .AlignToInterface <AnimationScript>(true); } catch { currentHost.AddMessage(MessageType.Error, false, "An error occcured whilst parsing script " + TranslateZScriptFile); TranslateZScriptFile = null; return; } } double z = TranslateZAnimationScript.ExecuteScript(Train, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed); Vector3 translationVector = new Vector3(TranslateZDirection); //Must clone translationVector.Rotate(Direction, Up, Side); translationVector *= z; Position += translationVector; } // rotation bool rotateX = RotateXFunction != null; bool rotateY = RotateYFunction != null; bool rotateZ = RotateZFunction != null; double radianX = 0.0; if (rotateX) { radianX = RotateXFunction.LastResult; if (UpdateFunctions) { radianX = RotateXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateXDamping != null) { RotateXDamping.Update(TimeElapsed, ref radianX, EnableDamping); } } double radianY = 0.0; if (rotateY) { radianY = RotateYFunction.LastResult; if (UpdateFunctions) { radianY = RotateYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateYDamping != null) { RotateYDamping.Update(TimeElapsed, ref radianY, EnableDamping); } } double radianZ = 0.0; if (rotateZ) { radianZ = RotateZFunction.LastResult; if (UpdateFunctions) { radianZ = RotateZFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } if (RotateZDamping != null) { RotateZDamping.Update(TimeElapsed, ref radianZ, EnableDamping); } } // texture shift bool shiftx = TextureShiftXFunction != null; bool shifty = TextureShiftYFunction != null; internalObject.TextureTranslation = Matrix4D.Identity; if (shiftx | shifty) { if (shiftx) { double x = TextureShiftXFunction.LastResult; if (UpdateFunctions) { x = TextureShiftXFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } x -= System.Math.Floor(x); internalObject.TextureTranslation *= Matrix4D.CreateTranslation(x * TextureShiftXDirection.X, x * TextureShiftXDirection.Y, 1.0); } if (shifty) { double y = TextureShiftYFunction.LastResult; if (UpdateFunctions) { y = TextureShiftYFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } y -= System.Math.Floor(y); internalObject.TextureTranslation *= Matrix4D.CreateTranslation(y * TextureShiftYDirection.X, y * TextureShiftYDirection.Y, 1.0); } } // led bool led = LEDFunction != null; double ledangle = 0.0; if (led) { ledangle = LEDFunction.LastResult; if (UpdateFunctions) { ledangle = LEDFunction.Perform(Train, CarIndex, Position, TrackPosition, SectionIndex, IsPartOfTrain, TimeElapsed, CurrentState); } } // null object if (States[CurrentState].Prototype == null) { return; } // led if (led) { /* * Edges: Vertices: * 0 - bottom 0 - bottom-left * 1 - left 1 - top-left * 2 - top 2 - top-right * 3 - right 3 - bottom-right * 4 - center * */ int v = 1; if (LEDClockwiseWinding) { /* winding is clockwise*/ if (ledangle < LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle < LEDLastAngle) { double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (lastEdge < currentEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { lastEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } { double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(cx, cy, cz); States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[currentEdge]; v += 2; } for (int j = currentEdge + 1; j < lastEdge; j++) { /* square-vertex to square-vertex */ States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge % 4].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge % 4].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge % 4].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(lastEdge + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(lx, ly, lz); v += 2; } } } } else { /* winding is counter-clockwise*/ if (ledangle > LEDInitialAngle) { ledangle = LEDInitialAngle; } if (ledangle > LEDLastAngle) { double currentEdgeFloat = System.Math.Floor(0.636619772367582 * (ledangle + 0.785398163397449)); int currentEdge = ((int)currentEdgeFloat % 4 + 4) % 4; double lastEdgeFloat = System.Math.Floor(0.636619772367582 * (LEDLastAngle + 0.785398163397449)); int lastEdge = ((int)lastEdgeFloat % 4 + 4) % 4; if (currentEdge < lastEdge | lastEdge == currentEdge & System.Math.Abs(currentEdgeFloat - lastEdgeFloat) > 2.0) { currentEdge += 4; } if (currentEdge == lastEdge) { /* current angle to last angle */ { double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(lx, ly, lz); v++; } { double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = t - System.Math.Floor(t); t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v].Coordinates = new Vector3(cx, cy, cz); v++; } } else { { /* current angle to square vertex */ double t = 0.5 + 0.636619772367582 * ledangle - currentEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double cx = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].X + t * LEDVectors[currentEdge % 4].X; double cy = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Y + t * LEDVectors[currentEdge % 4].Y; double cz = (1.0 - t) * LEDVectors[(currentEdge + 3) % 4].Z + t * LEDVectors[currentEdge % 4].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(currentEdge + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = new Vector3(cx, cy, cz); v += 2; } for (int j = currentEdge - 1; j > lastEdge; j--) { /* square-vertex to square-vertex */ States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = LEDVectors[(j + 3) % 4]; States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[j % 4]; v += 2; } { /* square vertex to last angle */ double t = 0.5 + 0.636619772367582 * LEDLastAngle - lastEdgeFloat; if (t < 0.0) { t = 0.0; } else if (t > 1.0) { t = 1.0; } t = 0.5 * (1.0 - System.Math.Tan(0.25 * (System.Math.PI - 2.0 * System.Math.PI * t))); double lx = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].X + t * LEDVectors[lastEdge].X; double ly = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Y + t * LEDVectors[lastEdge].Y; double lz = (1.0 - t) * LEDVectors[(lastEdge + 3) % 4].Z + t * LEDVectors[lastEdge].Z; States[CurrentState].Prototype.Mesh.Vertices[v + 0].Coordinates = new Vector3(lx, ly, lz); States[CurrentState].Prototype.Mesh.Vertices[v + 1].Coordinates = LEDVectors[lastEdge % 4]; v += 2; } } } } for (int j = v; v < 11; v++) { States[CurrentState].Prototype.Mesh.Vertices[j].Coordinates = LEDVectors[4]; } } // update prototype internalObject.Prototype = States[CurrentState].Prototype; // update VAO for led if required UpdateVAO = led; // update state // rotate internalObject.Rotate = Matrix4D.Identity; if (rotateX) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateXDirection.X, RotateXDirection.Y, -RotateXDirection.Z), 2.0 * System.Math.PI - radianX); } if (rotateY) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateYDirection.X, RotateYDirection.Y, -RotateYDirection.Z), 2.0 * System.Math.PI - radianY); } if (rotateZ) { internalObject.Rotate *= Matrix4D.CreateFromAxisAngle(new Vector3(RotateZDirection.X, RotateZDirection.Y, -RotateZDirection.Z), 2.0 * System.Math.PI - radianZ); } if (Camera != null && Camera.CurrentRestriction != CameraRestrictionMode.NotAvailable && Camera.CurrentRestriction != CameraRestrictionMode.Restricted3D) { internalObject.Rotate *= States[CurrentState].Translation * Matrix4D.CreateTranslation(-Position.X, -Position.Y, Position.Z); internalObject.Rotate *= (Matrix4D) new Transformation((Vector3)Camera.AbsoluteDirection, (Vector3)Camera.AbsoluteUp, (Vector3)Camera.AbsoluteSide); // translate double dx = -System.Math.Tan(Camera.Alignment.Yaw) - Camera.Alignment.Position.X; double dy = -System.Math.Tan(Camera.Alignment.Pitch) - Camera.Alignment.Position.Y; double dz = -Camera.Alignment.Position.Z; Vector3 add = Camera.AbsolutePosition + dx * Camera.AbsoluteSide + dy * Camera.AbsoluteUp + dz * Camera.AbsoluteDirection; internalObject.Translation = Matrix4D.CreateTranslation(add.X, add.Y, -add.Z); } else { internalObject.Rotate *= States[CurrentState].Translation; internalObject.Rotate *= (Matrix4D) new Transformation(Direction, Up, Side); // translate internalObject.Translation = Matrix4D.CreateTranslation(Position.X, Position.Y, -Position.Z); } // visibility changed // TouchElement is handled by another function. if (!IsTouch) { if (Show) { if (Camera != null) { currentHost.ShowObject(internalObject, ObjectType.Overlay); } else { currentHost.ShowObject(internalObject, ObjectType.Dynamic); } } else { currentHost.HideObject(internalObject); } } }
public override Asset Import(string path) { FBX fbx = FBX.Load(path); Model model = new Model(); Dictionary <long, object> components = new Dictionary <long, object>(); Dictionary <long, Matrix4D> transforms = new Dictionary <long, Matrix4D>(); Dictionary <long, string> triangulationErrors = new Dictionary <long, string>(); string name = Path.GetFileNameWithoutExtension(path); if (fbx == null) { SceneManager.Current.RaiseError($"File \"{name}\" could not be opened. Please ensure this is a binary FBX file."); return(null); } FBXElem objects = fbx.Elements.Find(e => e.ID == "Objects"); Matrix4D worldMatrix = createTransformFor(fbx.Elements.Find(e => e.ID == "GlobalSettings").Children[1], out Quaternion.RotationOrder order); foreach (FBXElem material in objects.Children.Where(e => e.ID == "Material")) { string matName = material.Properties[1].Value.ToString(); matName = matName.Substring(0, matName.IndexOf("::")); Material m = new Material { Name = matName }; components.Add((long)material.Properties[0].Value, m); Console.WriteLine($"Added material \"{matName}\" ({material.Properties[0].Value})"); } foreach (FBXElem video in objects.Children.Where(e => e.ID == "Video")) { FBXElem content = video.Children.Find(e => e.ID == "Content"); if (content.Properties[0].Size > 4) { components.Add((long)video.Properties[0].Value, (byte[])content.Properties[0].Value); } } IEnumerable <FBXElem> textures = objects.Children.Where(e => e.ID == "Texture"); foreach (FBXElem texture in textures) { string fullFile = texture.Children.Find(e => e.ID == "FileName").Properties[0].Value.ToString(); if (fullFile.IndexOf('.') == -1) { continue; } string file = Path.GetFileName(fullFile); Texture t = new Texture(); long videoKey = (long)fbx.Elements.Find(e => e.ID == "Connections").Children.Where(c => (long)c.Properties[2].Value == (long)texture.Properties[0].Value).First().Properties[1].Value; if (components.ContainsKey(videoKey)) { using (FileStream fs = new FileStream(Path.Combine(Path.GetDirectoryName(path), file), FileMode.Create)) using (BinaryWriter bw = new BinaryWriter(fs)) { bw.Write((byte[])components[videoKey]); } } t = SceneManager.Current.Content.Load(Path.GetFileName(file)); switch (fbx.Elements.Find(e => e.ID == "Connections").Children.Where(c => (long)c.Properties[1].Value == (long)texture.Properties[0].Value).First().Properties.Last().Value.ToString()) { case "NormalMap": t.Type = Texture.TextureType.Normal; break; case "SpecularColor": t.Type = Texture.TextureType.Specular; break; } if (!components.ContainsKey((long)texture.Properties[0].Value)) { components.Add((long)texture.Properties[0].Value, t); Console.WriteLine($"Added texture \"{file}\" ({texture.Properties[0].Value})"); } } foreach (FBXElem element in objects.Children.Where(e => e.ID == "Model")) { string modelName = element.Properties[1].Value.ToString(); modelName = modelName.Substring(0, modelName.IndexOf("::")); components.Add((long)element.Properties[0].Value, new ModelMesh { Name = modelName, Tag = (long)element.Properties[0].Value }); Console.WriteLine("Added model \"{0}\" ({1})", modelName, element.Properties[0].Value); FBXElem properties = element.Children.Find(c => c.ID == "Properties70"); Matrix4D m = Matrix4D.Identity; bool bRotationActive = false; Vector3 lclTranslation = Vector3.Zero; Quaternion lclRotation = Quaternion.Identity; Quaternion preRotation = Quaternion.Identity; Quaternion postRotation = Quaternion.Identity; Vector3 rotationPivot = Vector3.Zero; Vector3 rotationOffset = Vector3.Zero; Vector3 lclScaling = Vector3.One; Vector3 scalingPivot = Vector3.Zero; Vector3 scalingOffset = Vector3.Zero; Vector3 geoPosition = Vector3.Zero; Quaternion geoRotation = Quaternion.Identity; Vector3 geoScale = Vector3.One; FBXElem property; property = properties.Children.GetProperty("RotationActive"); if (property != null) { bRotationActive = ((int)property.Properties[4].Value == 1); } property = properties.Children.GetProperty("ScalingPivot"); if (property != null) { scalingPivot = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("Lcl Scaling"); if (property != null) { lclScaling = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("ScalingOffset"); if (property != null) { scalingOffset = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("RotationPivot"); if (property != null) { rotationPivot = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("PostRotation"); if (property != null) { postRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("Lcl Rotation"); if (property != null) { lclRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("PreRotation"); if (property != null) { preRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("RotationOffset"); if (property != null) { rotationOffset = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("Lcl Translation"); if (property != null) { lclTranslation = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("GeometricTranslation"); if (property != null) { geoPosition = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("GeometricRotation"); if (property != null) { geoRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("GeometricScaling"); if (property != null) { geoScale = new Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } m = Matrix4D.CreateTranslation(scalingPivot).Inverted() * Matrix4D.CreateScale(lclScaling) * Matrix4D.CreateTranslation(scalingPivot) * Matrix4D.CreateTranslation(scalingOffset) * Matrix4D.CreateTranslation(rotationPivot).Inverted() * Matrix4D.CreateFromQuaternion(postRotation) * Matrix4D.CreateFromQuaternion(lclRotation) * Matrix4D.CreateFromQuaternion(preRotation) * Matrix4D.CreateTranslation(rotationPivot) * Matrix4D.CreateTranslation(rotationOffset) * Matrix4D.CreateTranslation(lclTranslation); if (m != Matrix4D.Identity) { transforms.Add((long)element.Properties[0].Value, m); } } foreach (FBXElem element in objects.Children.Where(e => e.ID == "Geometry")) { bool bUVs = true; bool bNorms = true; bool bColours = true; bool bUseIndexNorm = false; bool bNeedsTriangulating = false; string geometryName = element.Properties[1].Value.ToString(); geometryName = geometryName.Substring(0, geometryName.IndexOf("::")); List <Vector3> verts = new List <Vector3>(); List <Vector3> norms = new List <Vector3>(); List <Vector2> uvs = new List <Vector2>(); List <Colour> colours = new List <Colour>(); double[] vertParts = (double[])element.Children.Find(e => e.ID == "Vertices").Properties[0].Value; for (int i = 0; i < vertParts.Length; i += 3) { verts.Add(new Vector3((float)vertParts[i + 0], (float)vertParts[i + 1], (float)vertParts[i + 2])); } SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->Vertices"); FBXElem normElem = element.Children.Find(e => e.ID == "LayerElementNormal"); if (normElem != null) { double[] normParts = (double[])normElem.Children.Find(e => e.ID == "Normals").Properties[0].Value; for (int i = 0; i < normParts.Length; i += 3) { norms.Add(new Vector3((float)normParts[i + 0], (float)normParts[i + 1], (float)normParts[i + 2])); } bUseIndexNorm = (normElem.Children.Find(e => e.ID == "MappingInformationType").Properties[0].Value.ToString() == "ByVertice"); SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->Normals"); } else { bNorms = false; } FBXElem colourElem = element.Children.Find(e => e.ID == "LayerElementColor"); if (colourElem != null) { double[] colourParts = (double[])colourElem.Children.Find(e => e.ID == "Colors").Properties[0].Value; FBXElem colourReferenceType = colourElem.Children.Find(e => e.ID == "ReferenceInformationType"); switch (colourReferenceType.Properties[0].Value.ToString()) { case "IndexToDirect": int[] colourIndicies = (int[])colourElem.Children.Find(e => e.ID == "ColorIndex").Properties[0].Value; for (int i = 0; i < colourIndicies.Length; i++) { int offset = colourIndicies[i] * 4; colours.Add(new Colour( (float)colourParts[offset + 0], (float)colourParts[offset + 1], (float)colourParts[offset + 2], (float)colourParts[offset + 3]) ); } break; case "Direct": bColours = false; break; default: throw new NotImplementedException($"Unsupported Colour Reference Type: {colourReferenceType.Properties[0].Value}"); } SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->Colours"); } else { bColours = false; } FBXElem uvElem = element.Children.Find(e => e.ID == "LayerElementUV"); if (uvElem != null) { double[] uvParts = (double[])uvElem.Children.Find(e => e.ID == "UV").Properties[0].Value; FBXElem uvReferenceType = uvElem.Children.Find(e => e.ID == "ReferenceInformationType"); if (uvReferenceType.Properties[0].Value.ToString() == "IndexToDirect") { List <Vector2> luvs = new List <Vector2>(); for (int i = 0; i < uvParts.Length; i += 2) { luvs.Add(new Vector2((float)uvParts[i + 0], 1 - (float)uvParts[i + 1])); } int[] uvindicies = (int[])uvElem.Children.Find(e => e.ID == "UVIndex").Properties[0].Value; for (int i = 0; i < uvindicies.Length; i++) { if (uvindicies[i] == -1) { uvs.Add(Vector2.Zero); } else { uvs.Add(luvs[uvindicies[i]]); } } } else { for (int i = 0; i < uvParts.Length; i += 2) { uvs.Add(new Vector2((float)uvParts[i + 0], (float)uvParts[i + 1])); } } SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->UVs"); } else { bUVs = false; } int[] indicies = (int[])element.Children.Find(e => e.ID == "PolygonVertexIndex").Properties[0].Value; List <FBXFace> faces = new List <FBXFace>(); FBXFace face = new FBXFace(); int j = 0; for (int i = 0; i < indicies.Length; i++) { bool bFace = false; int index = indicies[i]; if (index < 0) { bFace = true; index = (index * -1) - 1; } j++; face.AddVertex(verts[index], bNorms ? norms[bUseIndexNorm ? index : i] : Vector3.Zero, bUVs ? uvs[i] : Vector2.Zero, bColours ? colours[i] : Colour.White); if (bFace) { if (j > 3) { triangulationErrors.Add((long)element.Properties[0].Value, geometryName); bNeedsTriangulating = true; break; } faces.Add(face); face = new FBXFace(); j = 0; } } List <ModelMeshPart> parts = new List <ModelMeshPart>(); if (!bNeedsTriangulating) { SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->Faces"); FBXElem elemMaterial = element.Children.Find(e => e.ID == "LayerElementMaterial"); if (elemMaterial != null) { int[] faceMaterials = (int[])elemMaterial.Children.Find(e => e.ID == "Materials").Properties[0].Value; for (int i = 0; i < faceMaterials.Length; i++) { faces[i].MaterialID = faceMaterials[i]; } SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->Materials"); } IEnumerable <IGrouping <int, FBXFace> > materialGroups = faces.GroupBy(f => f.MaterialID); int processedFaceCount = 0, processedGroupCount = 0; foreach (IGrouping <int, FBXFace> materialGroup in materialGroups) { IEnumerable <IGrouping <int, FBXFace> > smoothingGroups = materialGroup.GroupBy(f => f.SmoothingGroup); foreach (IGrouping <int, FBXFace> smoothingGroup in smoothingGroups) { ModelMeshPart meshpart = new ModelMeshPart { PrimitiveType = Flummery.Core.PrimitiveType.Triangles }; processedFaceCount = 0; foreach (FBXFace groupface in smoothingGroup) { foreach (Vertex vert in groupface.Vertices) { meshpart.AddVertex(vert.Position, vert.Normal, vert.UV, vert.Colour); } processedFaceCount++; if (processedFaceCount % 250 == 0) { SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->MeshPart[{processedGroupCount}]->Face[{processedFaceCount}]"); } } meshpart.Key = materialGroup.Key; parts.Add(meshpart); SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}->MeshPart"); processedGroupCount++; } } } components.Add((long)element.Properties[0].Value, parts); SceneManager.Current.UpdateProgress($"Processed {element.Properties[1].Value}"); } Dictionary <long, BoneType> nodeAttributes = new Dictionary <long, BoneType>(); Dictionary <long, object> nodeAttachments = new Dictionary <long, object>(); foreach (FBXElem nodeAttribute in objects.Children.Where(e => e.ID == "NodeAttribute")) { FBXElem typeFlags = nodeAttribute.Children.Find(e => e.ID == "TypeFlags"); if (typeFlags != null) { switch (typeFlags.Properties[0].Value.ToString().ToLower()) { case "light": LIGHT light = new LIGHT(); FBXElem lightType = nodeAttribute.Children.Find(c => c.ID == "Properties70").Children.GetProperty("LightType"); light.Type = (LIGHT.LightType)(lightType == null ? 0 : lightType.Properties[4].Value); nodeAttributes.Add((long)nodeAttribute.Properties[0].Value, BoneType.Light); nodeAttachments.Add((long)nodeAttribute.Properties[0].Value, light); break; default: // null node break; } } } string[] connectionOrder = new string[] { "System.Collections.Generic.List`1[Flummery.Core.ModelMeshPart]", "Flummery.Core.Texture", "Flummery.Core.Material", "Flummery.Core.ModelMesh" }; FBXElem connections = fbx.Elements.Find(e => e.ID == "Connections"); HashSet <long> loaded = new HashSet <long>(); foreach (string connectionType in connectionOrder) { IEnumerable <FBXElem> connectionsOfType = connections.Children.Where(c => components.ContainsKey((long)c.Properties[1].Value) && components[(long)c.Properties[1].Value].GetType().ToString() == connectionType); foreach (FBXElem connection in connectionsOfType) { long keyA = (long)connection.Properties[1].Value; long keyB = (long)connection.Properties[2].Value; Console.WriteLine("{0} is connected to {1} :: {2}", keyA, keyB, connectionType); switch (connectionType) { case "Flummery.Core.ModelMesh": int boneID; if (keyB == 0) { boneID = model.AddMesh((ModelMesh)components[keyA]); model.SetName(((ModelMesh)components[keyA]).Name, boneID); if (transforms.ContainsKey(keyA)) { model.SetTransform(transforms[keyA], boneID); } FBXElem attribute = connections.Children.FirstOrDefault(c => nodeAttributes.ContainsKey((long)c.Properties[1].Value) && (long)c.Properties[2].Value == keyA); if (attribute != null) { keyA = (long)attribute.Properties[1].Value; if (nodeAttributes.ContainsKey(keyA)) { model.Bones[boneID].Type = nodeAttributes[keyA]; } if (nodeAttachments.ContainsKey(keyA)) { model.Bones[boneID].Attachment = nodeAttachments[keyA]; } } } else { ModelMesh parent = model.FindMesh(keyB); if (parent != null) { boneID = model.AddMesh((ModelMesh)components[keyA], parent.Parent.Index); model.SetName(((ModelMesh)components[keyA]).Name, boneID); if (transforms.ContainsKey(keyA)) { model.SetTransform(transforms[keyA], boneID); } } else { if (!components.ContainsKey(keyB)) { Console.WriteLine("Components doesn't contain {0}", keyB); } else { Console.WriteLine("Couldn't find {0}", ((ModelMesh)components[keyB]).Name); } } } break; case "Flummery.Core.Texture": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.Core.Material") { if (loaded.Add(keyA)) { ((Material)components[keyB]).Texture = (Texture)components[keyA]; //SceneManager.Current.Add((Material)components[keyB]); } } else { Console.WriteLine("{0} is of unknown type {1}", keyA, components[keyA].GetType().ToString()); Console.WriteLine("{0} is of unknown type {1}", keyB, components[keyB].GetType().ToString()); } break; case "System.Collections.Generic.List`1[Flummery.Core.ModelMeshPart]": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.Core.ModelMesh") { if (triangulationErrors.ContainsKey(keyA)) { triangulationErrors[keyA] += " (geometry of " + ((ModelMesh)components[keyB]).Name + ")"; } foreach (ModelMeshPart part in (List <ModelMeshPart>)components[keyA]) { ((ModelMesh)components[keyB]).AddModelMeshPart(part); } } break; case "Flummery.Core.Material": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.Core.ModelMesh") { List <FBXElem> materialLookup = connections.Children.Where(c => (long)c.Properties[2].Value == keyB).ToList(); for (int i = materialLookup.Count - 1; i > -1; i--) { if (!connectionsOfType.Any(c => (long)c.Properties[1].Value == (long)materialLookup[i].Properties[1].Value)) { materialLookup.RemoveAt(i); } } foreach (ModelMeshPart part in ((ModelMesh)components[keyB]).MeshParts) { if ((long)materialLookup[(int)part.Key].Properties[1].Value == keyA) { part.Material = (Material)components[keyA]; SceneManager.Current.Add(part.Material); } } } break; default: Console.WriteLine("{0} is of unknown type {1}", keyA, components[keyA].GetType().ToString()); if (components.ContainsKey(keyB)) { Console.WriteLine("{0} is of unknown type {1}", keyB, components[keyB].GetType().ToString()); } Console.WriteLine("==="); break; } } } if (triangulationErrors.Count > 0) { SceneManager.Current.UpdateProgress($"Failed to load {name}"); string error = $"File \"{name}\" has part{(triangulationErrors.Count > 1 ? "s" : "")} that need been triangulating! Please triangulate the following:"; foreach (KeyValuePair <long, string> kvp in triangulationErrors) { error += $"\r\n{kvp.Value}"; } SceneManager.Current.RaiseError(error); return(null); } else { SceneManager.Current.UpdateProgress($"Loaded {name}"); model.Santise(); //if (worldMatrix != Matrix4D.Identity) { ModelManipulator.Freeze(model, worldMatrix); } ModelManipulator.FlipAxis(model, Axis.Z, true); return(model); } }
public void RenderFace(Shader Shader, ObjectState State, MeshFace Face, Vector3 EyePosition, bool IsDebugTouchMode = false) { if (State.Prototype.Mesh.Vertices.Length < 1) { return; } VertexTemplate[] vertices = State.Prototype.Mesh.Vertices; MeshMaterial material = State.Prototype.Mesh.Materials[Face.Material]; VertexArrayObject VAO = (VertexArrayObject)State.Prototype.Mesh.VAO; VertexArrayObject NormalsVAO = (VertexArrayObject)State.Prototype.Mesh.NormalsVAO; if (!OptionBackFaceCulling || (Face.Flags & MeshFace.Face2Mask) != 0) { GL.Disable(EnableCap.CullFace); } else if (OptionBackFaceCulling) { if ((Face.Flags & MeshFace.Face2Mask) == 0) { GL.Enable(EnableCap.CullFace); } } // matrix Matrix4D modelMatrix = State.Scale * State.Rotate * State.Translation * Matrix4D.CreateTranslation(-EyePosition); Matrix4D modelViewMatrix = modelMatrix * CurrentViewMatrix; Shader.SetCurrentProjectionMatrix(CurrentProjectionMatrix); Shader.SetCurrentModelViewMatrix(modelViewMatrix); Shader.SetCurrentNormalMatrix(Matrix4D.Transpose(Matrix4D.Invert(modelViewMatrix))); Shader.SetCurrentTextureMatrix(State.TextureTranslation); if (OptionWireFrame || IsDebugTouchMode) { VAO.Bind(); VAO.Draw(Shader.VertexLayout, PrimitiveType.LineLoop, Face.IboStartIndex, Face.Vertices.Length); VAO.UnBind(); return; } // lighting if (material.NighttimeTexture == null) { if (OptionLighting) { Shader.SetIsLight(true); Shader.SetLightPosition(new Vector3(Lighting.OptionLightPosition.X, Lighting.OptionLightPosition.Y, -Lighting.OptionLightPosition.Z)); Shader.SetLightAmbient(new Color4(Lighting.OptionAmbientColor.R, Lighting.OptionAmbientColor.G, Lighting.OptionAmbientColor.B, 255)); Shader.SetLightDiffuse(new Color4(Lighting.OptionDiffuseColor.R, Lighting.OptionDiffuseColor.G, Lighting.OptionDiffuseColor.B, 255)); Shader.SetLightSpecular(new Color4(Lighting.OptionSpecularColor.R, Lighting.OptionSpecularColor.G, Lighting.OptionSpecularColor.B, 255)); Shader.SetMaterialAmbient(new Color4(material.Color.R, material.Color.G, material.Color.B, material.Color.A)); // TODO Shader.SetMaterialDiffuse(new Color4(material.Color.R, material.Color.G, material.Color.B, material.Color.A)); Shader.SetMaterialSpecular(new Color4(material.Color.R, material.Color.G, material.Color.B, material.Color.A)); // TODO if ((material.Flags & MeshMaterial.EmissiveColorMask) != 0) { Shader.SetMaterialEmission(new Color4(material.EmissiveColor.R, material.EmissiveColor.G, material.EmissiveColor.B, 255)); } else { Shader.SetMaterialEmission(new Color4(0.0f, 0.0f, 0.0f, 1.0f)); } Shader.SetMaterialShininess(1.0f); Lighting.OptionLightingResultingAmount = (Lighting.OptionAmbientColor.R + Lighting.OptionAmbientColor.G + Lighting.OptionAmbientColor.B) / 480.0f; if (Lighting.OptionLightingResultingAmount > 1.0f) { Lighting.OptionLightingResultingAmount = 1.0f; } } else { Shader.SetMaterialAmbient(new Color4(material.Color.R, material.Color.G, material.Color.B, material.Color.A)); // TODO } } else { Shader.SetMaterialAmbient(new Color4(material.Color.R, material.Color.G, material.Color.B, material.Color.A)); // TODO } // fog if (OptionFog) { Shader.SetIsFog(true); Shader.SetFogStart(Fog.Start); Shader.SetFogEnd(Fog.End); Shader.SetFogColor(new Color4(Fog.Color.R, Fog.Color.G, Fog.Color.B, 255)); } PrimitiveType DrawMode; switch (Face.Flags & MeshFace.FaceTypeMask) { case MeshFace.FaceTypeTriangles: DrawMode = PrimitiveType.Triangles; break; case MeshFace.FaceTypeTriangleStrip: DrawMode = PrimitiveType.TriangleStrip; break; case MeshFace.FaceTypeQuads: DrawMode = PrimitiveType.Quads; break; case MeshFace.FaceTypeQuadStrip: DrawMode = PrimitiveType.QuadStrip; break; default: DrawMode = PrimitiveType.Polygon; break; } // daytime polygon { // texture if (material.DaytimeTexture != null) { if (currentHost.LoadTexture(material.DaytimeTexture, (OpenGlTextureWrapMode)material.WrapMode)) { GL.Enable(EnableCap.Texture2D); Shader.SetIsTexture(true); Shader.SetTexture(0); GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode].Name); } } // blend mode float factor; if (material.BlendMode == MeshMaterialBlendMode.Additive) { factor = 1.0f; GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One); Shader.SetIsFog(false); } else if (material.NighttimeTexture == null) { float blend = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } factor = 1.0f - 0.7f * blend; } else { factor = 1.0f; } Shader.SetBrightness(factor); float alphaFactor; if (material.GlowAttenuationData != 0) { alphaFactor = (float)Glow.GetDistanceFactor(modelMatrix, vertices, ref Face, material.GlowAttenuationData); } else { alphaFactor = 1.0f; } Shader.SetOpacity(inv255 * material.Color.A * alphaFactor); // render polygon VAO.Bind(); VAO.Draw(Shader.VertexLayout, DrawMode, Face.IboStartIndex, Face.Vertices.Length); VAO.UnBind(); GL.BindTexture(TextureTarget.Texture2D, 0); } // nighttime polygon if (material.NighttimeTexture != null && currentHost.LoadTexture(material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode)) { // texture GL.Enable(EnableCap.Texture2D); Shader.SetIsTexture(true); Shader.SetTexture(0); GL.BindTexture(TextureTarget.Texture2D, material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode].Name); GL.Enable(EnableCap.Blend); // alpha test GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Greater, 0.0f); // blend mode float alphaFactor; if (material.GlowAttenuationData != 0) { alphaFactor = (float)Glow.GetDistanceFactor(modelMatrix, vertices, ref Face, material.GlowAttenuationData); float blend = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } alphaFactor *= blend; } else { alphaFactor = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (alphaFactor > 1.0f) { alphaFactor = 1.0f; } } Shader.SetOpacity(alphaFactor); // render polygon VAO.Bind(); VAO.Draw(Shader.VertexLayout, DrawMode, Face.IboStartIndex, Face.Vertices.Length); VAO.UnBind(); GL.BindTexture(TextureTarget.Texture2D, 0); RestoreBlendFunc(); RestoreAlphaFunc(); } GL.Disable(EnableCap.Texture2D); // normals if (OptionNormals) { Shader.SetIsTexture(false); Shader.SetBrightness(1.0f); Shader.SetOpacity(1.0f); NormalsVAO.Bind(); NormalsVAO.Draw(Shader.VertexLayout, PrimitiveType.Lines, Face.NormalsIboStartIndex, Face.Vertices.Length * 2); NormalsVAO.UnBind(); } // finalize if (material.BlendMode == MeshMaterialBlendMode.Additive) { RestoreBlendFunc(); } }
public void RenderFaceImmediateMode(ObjectState State, MeshFace Face, Vector3 EyePosition, bool IsDebugTouchMode = false) { if (State.Prototype.Mesh.Vertices.Length < 1) { return; } VertexTemplate[] vertices = State.Prototype.Mesh.Vertices; MeshMaterial material = State.Prototype.Mesh.Materials[Face.Material]; if (!OptionBackFaceCulling || (Face.Flags & MeshFace.Face2Mask) != 0) { GL.Disable(EnableCap.CullFace); } else if (OptionBackFaceCulling) { if ((Face.Flags & MeshFace.Face2Mask) == 0) { GL.Enable(EnableCap.CullFace); } } Matrix4D modelMatrix = State.Scale * State.Rotate * State.Translation * Matrix4D.CreateTranslation(-EyePosition); // matrix unsafe { GL.MatrixMode(MatrixMode.Projection); GL.PushMatrix(); fixed(double *matrixPointer = &CurrentProjectionMatrix.Row0.X) { GL.LoadMatrix(matrixPointer); } GL.MatrixMode(MatrixMode.Modelview); GL.PushMatrix(); fixed(double *matrixPointer = &CurrentViewMatrix.Row0.X) { GL.LoadMatrix(matrixPointer); } double *matrixPointer2 = &modelMatrix.Row0.X; { GL.MultMatrix(matrixPointer2); } GL.MatrixMode(MatrixMode.Texture); GL.PushMatrix(); fixed(double *matrixPointer = &State.TextureTranslation.Row0.X) { GL.LoadMatrix(matrixPointer); } } if (OptionWireFrame) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line); } // lighting if (material.NighttimeTexture == null) { if (OptionLighting) { GL.Enable(EnableCap.Lighting); if ((material.Flags & MeshMaterial.EmissiveColorMask) != 0) { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new Color4(material.EmissiveColor.R, material.EmissiveColor.G, material.EmissiveColor.B, 255)); } else { GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Emission, new Color4(0.0f, 0.0f, 0.0f, 1.0f)); } } } // fog if (OptionFog) { GL.Enable(EnableCap.Fog); } PrimitiveType DrawMode; switch (Face.Flags & MeshFace.FaceTypeMask) { case MeshFace.FaceTypeTriangles: DrawMode = PrimitiveType.Triangles; break; case MeshFace.FaceTypeTriangleStrip: DrawMode = PrimitiveType.TriangleStrip; break; case MeshFace.FaceTypeQuads: DrawMode = PrimitiveType.Quads; break; case MeshFace.FaceTypeQuadStrip: DrawMode = PrimitiveType.QuadStrip; break; default: DrawMode = PrimitiveType.Polygon; break; } // daytime polygon { // texture if (material.DaytimeTexture != null) { if (currentHost.LoadTexture(material.DaytimeTexture, (OpenGlTextureWrapMode)material.WrapMode)) { GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, material.DaytimeTexture.OpenGlTextures[(int)material.WrapMode].Name); } } // blend mode float factor; if (material.BlendMode == MeshMaterialBlendMode.Additive) { factor = 1.0f; GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.One); GL.Disable(EnableCap.Fog); } else if (material.NighttimeTexture == null) { float blend = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } factor = 1.0f - 0.7f * blend; } else { factor = 1.0f; } float alphaFactor; if (material.GlowAttenuationData != 0) { alphaFactor = (float)Glow.GetDistanceFactor(modelMatrix, vertices, ref Face, material.GlowAttenuationData); } else { alphaFactor = 1.0f; } GL.Begin(DrawMode); if (OptionWireFrame) { GL.Color4(inv255 * material.Color.R * factor, inv255 * material.Color.G * factor, inv255 * material.Color.B * factor, 1.0f); } else { GL.Color4(inv255 * material.Color.R * factor, inv255 * material.Color.G * factor, inv255 * material.Color.B * factor, inv255 * material.Color.A * alphaFactor); } for (int i = 0; i < Face.Vertices.Length; i++) { GL.Normal3(Face.Vertices[i].Normal.X, Face.Vertices[i].Normal.Y, -Face.Vertices[i].Normal.Z); GL.TexCoord2(vertices[Face.Vertices[i].Index].TextureCoordinates.X, vertices[Face.Vertices[i].Index].TextureCoordinates.Y); if (vertices[Face.Vertices[i].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)vertices[Face.Vertices[i].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3(vertices[Face.Vertices[i].Index].Coordinates.X, vertices[Face.Vertices[i].Index].Coordinates.Y, -vertices[Face.Vertices[i].Index].Coordinates.Z); } GL.End(); GL.BindTexture(TextureTarget.Texture2D, 0); } // nighttime polygon if (material.NighttimeTexture != null && currentHost.LoadTexture(material.NighttimeTexture, (OpenGlTextureWrapMode)material.WrapMode)) { // texture GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, material.NighttimeTexture.OpenGlTextures[(int)material.WrapMode].Name); GL.Enable(EnableCap.Blend); // alpha test GL.Enable(EnableCap.AlphaTest); GL.AlphaFunc(AlphaFunction.Greater, 0.0f); // blend mode float alphaFactor; if (material.GlowAttenuationData != 0) { alphaFactor = (float)Glow.GetDistanceFactor(modelMatrix, vertices, ref Face, material.GlowAttenuationData); float blend = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (blend > 1.0f) { blend = 1.0f; } alphaFactor *= blend; } else { alphaFactor = inv255 * material.DaytimeNighttimeBlend + 1.0f - Lighting.OptionLightingResultingAmount; if (alphaFactor > 1.0f) { alphaFactor = 1.0f; } } GL.Begin(DrawMode); if (OptionWireFrame) { GL.Color4(inv255 * material.Color.R, inv255 * material.Color.G, inv255 * material.Color.B, 1.0f); } else { GL.Color4(inv255 * material.Color.R, inv255 * material.Color.G, inv255 * material.Color.B, inv255 * material.Color.A * alphaFactor); } for (int i = 0; i < Face.Vertices.Length; i++) { GL.Normal3(Face.Vertices[i].Normal.X, Face.Vertices[i].Normal.Y, -Face.Vertices[i].Normal.Z); GL.TexCoord2(vertices[Face.Vertices[i].Index].TextureCoordinates.X, vertices[Face.Vertices[i].Index].TextureCoordinates.Y); if (vertices[Face.Vertices[i].Index] is ColoredVertex) { ColoredVertex v = (ColoredVertex)vertices[Face.Vertices[i].Index]; GL.Color3(v.Color.R, v.Color.G, v.Color.B); } GL.Vertex3(vertices[Face.Vertices[i].Index].Coordinates.X, vertices[Face.Vertices[i].Index].Coordinates.Y, -vertices[Face.Vertices[i].Index].Coordinates.Z); } GL.End(); GL.BindTexture(TextureTarget.Texture2D, 0); RestoreBlendFunc(); RestoreAlphaFunc(); } GL.Disable(EnableCap.Texture2D); // normals if (OptionNormals) { for (int i = 0; i < Face.Vertices.Length; i++) { GL.Begin(PrimitiveType.Lines); GL.Color4(new Color4(material.Color.R, material.Color.G, material.Color.B, 255)); GL.Vertex3(vertices[Face.Vertices[i].Index].Coordinates.X, vertices[Face.Vertices[i].Index].Coordinates.Y, -vertices[Face.Vertices[i].Index].Coordinates.Z); GL.Vertex3(vertices[Face.Vertices[i].Index].Coordinates.X + Face.Vertices[i].Normal.X, vertices[Face.Vertices[i].Index].Coordinates.Y + +Face.Vertices[i].Normal.Z, -(vertices[Face.Vertices[i].Index].Coordinates.Z + Face.Vertices[i].Normal.Z)); GL.End(); } } // finalize if (OptionWireFrame) { GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } if (material.BlendMode == MeshMaterialBlendMode.Additive) { RestoreBlendFunc(); } GL.PopMatrix(); GL.MatrixMode(MatrixMode.Modelview); GL.PopMatrix(); GL.MatrixMode(MatrixMode.Projection); GL.PopMatrix(); }