void AddEntities(ThnScript thn) { foreach (var kv in thn.Entities) { if (Objects.ContainsKey(kv.Key)) { continue; } if ((kv.Value.ObjectFlags & ThnObjectFlags.Reference) == ThnObjectFlags.Reference) { continue; } var obj = new ThnObject(); obj.Name = kv.Key; obj.Translate = kv.Value.Position ?? Vector3.Zero; obj.Rotate = kv.Value.RotationMatrix ?? Matrix4.Identity; //PlayerShip object if (spawnObjects && scriptContext.PlayerShip != null && kv.Value.Type == EntityTypes.Compound && kv.Value.Template.Equals("playership", StringComparison.InvariantCultureIgnoreCase)) { obj.Object = scriptContext.PlayerShip; obj.Object.RenderComponent.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; obj.Object.RenderComponent.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; obj.Object.RenderComponent.NoFog = kv.Value.NoFog; ((ModelRenderer)obj.Object.RenderComponent).LightGroup = kv.Value.LightGroup; obj.Entity = kv.Value; Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(transform); obj.HpMount = scriptContext.PlayerShip.GetHardpoint("HpMount"); World.Objects.Add(obj.Object); Objects.Add(kv.Key, obj); continue; } var template = kv.Value.Template; string replacement; if (scriptContext != null && scriptContext.Substitutions.TryGetValue(kv.Value.Template, out replacement)) { template = replacement; } if (spawnObjects && kv.Value.Type == EntityTypes.Compound) { bool getHpMount = false; //Fetch model IDrawable drawable; switch (kv.Value.MeshCategory.ToLowerInvariant()) { case "solar": drawable = gameData.GetSolar(template); break; case "ship": case "spaceship": getHpMount = true; var sh = gameData.GetShip(template); sh.LoadResources(); drawable = sh.Drawable; break; case "prop": drawable = gameData.GetProp(template); break; case "room": drawable = gameData.GetRoom(template); break; case "equipment cart": drawable = gameData.GetCart(template); break; case "equipment": var eq = gameData.GetEquipment(template); eq.LoadResources(); drawable = eq.GetDrawable(); break; case "asteroid": drawable = gameData.GetAsteroid(kv.Value.Template); break; default: throw new NotImplementedException("Mesh Category " + kv.Value.MeshCategory); } if (kv.Value.UserFlag != 0) { //This is a starsphere var transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(kv.Value.Position ?? Vector3.Zero); layers.Add(new Tuple <IDrawable, Matrix4, int>(drawable, transform, kv.Value.SortGroup)); } else { obj.Object = new GameObject(drawable, game.GetService <ResourceManager>(), true, false); obj.Object.Name = kv.Value.Name; obj.Object.PhysicsComponent = null; //Jitter seems to interfere with directly setting orientation if (getHpMount) { obj.HpMount = obj.Object.GetHardpoint("HpMount"); } var r = (ModelRenderer)obj.Object.RenderComponent; r.LightGroup = kv.Value.LightGroup; r.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; r.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; //HIDDEN just seems to be an editor flag? //r.Hidden = (kv.Value.ObjectFlags & ThnObjectFlags.Hidden) == ThnObjectFlags.Hidden; r.NoFog = kv.Value.NoFog; } } else if (kv.Value.Type == EntityTypes.PSys) { var fx = gameData.GetEffect(kv.Value.Template); obj.Object = new GameObject(); obj.Object.RenderComponent = new ParticleEffectRenderer(fx) { Active = false }; } else if (kv.Value.Type == EntityTypes.Scene) { if (hasScene) { //throw new Exception("Thn can only have one scene"); //TODO: This needs to be handled better continue; } var amb = kv.Value.Ambient.Value; if (amb.X == 0 && amb.Y == 0 && amb.Z == 0) { continue; } hasScene = true; Renderer.SystemLighting.Ambient = new Color4(amb.X / 255f, amb.Y / 255f, amb.Z / 255f, 1); } else if (kv.Value.Type == EntityTypes.Light) { var lt = new DynamicLight(); lt.LightGroup = kv.Value.LightGroup; lt.Active = kv.Value.LightProps.On; lt.Light = kv.Value.LightProps.Render; obj.Light = lt; obj.LightDir = lt.Light.Direction; if (kv.Value.RotationMatrix.HasValue) { var m = kv.Value.RotationMatrix.Value; lt.Light.Direction = (new Vector4(lt.Light.Direction.Normalized(), 0) * m).Xyz.Normalized(); } if (Renderer != null) { Renderer.SystemLighting.Lights.Add(lt); } } else if (kv.Value.Type == EntityTypes.Camera) { obj.Camera = new ThnCameraTransform(); obj.Camera.Position = kv.Value.Position.Value; obj.Camera.Orientation = kv.Value.RotationMatrix ?? Matrix4.Identity; obj.Camera.FovH = kv.Value.FovH ?? obj.Camera.FovH; obj.Camera.AspectRatio = kv.Value.HVAspect ?? obj.Camera.AspectRatio; } else if (kv.Value.Type == EntityTypes.Marker) { obj.Object = new GameObject(); obj.Object.Name = "Marker"; obj.Object.Nickname = ""; } else if (kv.Value.Type == EntityTypes.Sound) { obj.Sound = new ThnSound(kv.Value.Template, game.GetService <SoundManager>(), kv.Value.AudioProps, obj); obj.Sound.Spatial = (kv.Value.ObjectFlags & ThnObjectFlags.Spatial) == ThnObjectFlags.Spatial; } if (obj.Object != null) { Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(transform); World.Objects.Add(obj.Object); } obj.Entity = kv.Value; Objects[kv.Key] = obj; } }
public Cutscene(IEnumerable <ThnScript> scripts, FreelancerGame game) { camera = new ThnCamera(game.Viewport); Renderer = new SystemRenderer(camera, game.GameData, game.ResourceManager); World = new GameWorld(Renderer); //thn = script; var evs = new List <ThnEvent>(); bool hasScene = false; List <Tuple <IDrawable, Matrix4, int> > layers = new List <Tuple <IDrawable, Matrix4, int> >(); foreach (var thn in scripts) { foreach (var ev in thn.Events) { evs.Add(ev); } foreach (var kv in thn.Entities) { if ((kv.Value.ObjectFlags & ThnObjectFlags.Reference) == ThnObjectFlags.Reference) { continue; } var obj = new ThnObject(); obj.Name = kv.Key; obj.Translate = kv.Value.Position ?? Vector3.Zero; obj.Rotate = kv.Value.RotationMatrix ?? Matrix4.Identity; if (kv.Value.Type == EntityTypes.Compound) { //Fetch model IDrawable drawable; switch (kv.Value.MeshCategory.ToLowerInvariant()) { case "solar": drawable = game.GameData.GetSolar(kv.Value.Template); break; case "spaceship": var sh = game.GameData.GetShip(kv.Value.Template); drawable = sh.Drawable; break; case "prop": drawable = game.GameData.GetProp(kv.Value.Template); break; case "room": drawable = game.GameData.GetRoom(kv.Value.Template); break; case "equipment cart": drawable = game.GameData.GetCart(kv.Value.Template); break; case "equipment": var eq = game.GameData.GetEquipment(kv.Value.Template); drawable = eq.GetDrawable(); break; case "asteroid": drawable = game.GameData.GetAsteroid(kv.Value.Template); break; default: throw new NotImplementedException("Mesh Category " + kv.Value.MeshCategory); } if (kv.Value.UserFlag != 0) { //This is a starsphere var transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(kv.Value.Position ?? Vector3.Zero); layers.Add(new Tuple <IDrawable, Matrix4, int>(drawable, transform, kv.Value.SortGroup)); } else { obj.Object = new GameObject(drawable, game.ResourceManager, false); obj.Object.PhysicsComponent = null; //Jitter seems to interfere with directly setting orientation var r = (ModelRenderer)obj.Object.RenderComponent; r.LightGroup = kv.Value.LightGroup; r.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; r.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; //HIDDEN just seems to be an editor flag? //r.Hidden = (kv.Value.ObjectFlags & ThnObjectFlags.Hidden) == ThnObjectFlags.Hidden; r.NoFog = kv.Value.NoFog; } } else if (kv.Value.Type == EntityTypes.PSys) { var fx = game.GameData.GetEffect(kv.Value.Template); obj.Object = new GameObject(); obj.Object.RenderComponent = new ParticleEffectRenderer(fx) { Active = false }; } else if (kv.Value.Type == EntityTypes.Scene) { if (hasScene) { //throw new Exception("Thn can only have one scene"); //TODO: This needs to be handled better continue; } var amb = kv.Value.Ambient.Value; if (amb.X == 0 && amb.Y == 0 && amb.Z == 0) { continue; } hasScene = true; Renderer.SystemLighting.Ambient = new Color4(amb.X / 255f, amb.Y / 255f, amb.Z / 255f, 1); } else if (kv.Value.Type == EntityTypes.Light) { var lt = new DynamicLight(); lt.LightGroup = kv.Value.LightGroup; lt.Active = kv.Value.LightProps.On; lt.Light = kv.Value.LightProps.Render; obj.Light = lt; if (kv.Value.RotationMatrix.HasValue) { var m = kv.Value.RotationMatrix.Value; lt.Light.Direction = (new Vector4(lt.Light.Direction.Normalized(), 0) * m).Xyz.Normalized(); } Renderer.SystemLighting.Lights.Add(lt); } else if (kv.Value.Type == EntityTypes.Camera) { obj.Camera = new ThnCameraTransform(); obj.Camera.Position = kv.Value.Position.Value; obj.Camera.Orientation = kv.Value.RotationMatrix ?? Matrix4.Identity; obj.Camera.FovH = kv.Value.FovH ?? obj.Camera.FovH; obj.Camera.AspectRatio = kv.Value.HVAspect ?? obj.Camera.AspectRatio; } else if (kv.Value.Type == EntityTypes.Marker) { obj.Object = new GameObject(); obj.Object.Name = "Marker"; obj.Object.Nickname = ""; } if (obj.Object != null) { Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.Transform = (kv.Value.RotationMatrix ?? Matrix4.Identity) * Matrix4.CreateTranslation(transform); World.Objects.Add(obj.Object); } obj.Entity = kv.Value; Objects.Add(kv.Key, obj); } } evs.Sort((x, y) => x.Time.CompareTo(y.Time)); foreach (var item in evs) { events.Enqueue(item); } //Add starspheres in the right order layers.Sort((x, y) => x.Item3.CompareTo(y.Item3)); Renderer.StarSphereModels = new IDrawable[layers.Count]; Renderer.StarSphereWorlds = new Matrix4[layers.Count]; for (int i = 0; i < layers.Count; i++) { Renderer.StarSphereModels[i] = layers[i].Item1; Renderer.StarSphereWorlds[i] = layers[i].Item2; } //Add objects to the renderer World.RegisterAll(); }
public void ConstructEntities(Dictionary <string, ThnObject> objects, bool spawnObjects) { this.Objects = objects; foreach (var kv in thn.Entities) { if (Objects.ContainsKey(kv.Key)) { continue; } if ((kv.Value.ObjectFlags & ThnObjectFlags.Reference) == ThnObjectFlags.Reference) { continue; } var obj = new ThnObject(); obj.Name = kv.Key; obj.Translate = kv.Value.Position ?? Vector3.Zero; obj.Rotate = kv.Value.RotationMatrix ?? Matrix4x4.Identity; //PlayerShip object if (spawnObjects && Cutscene.PlayerShip != null && kv.Value.Type == EntityTypes.Compound && kv.Value.Template.Equals("playership", StringComparison.InvariantCultureIgnoreCase)) { obj.Object = Cutscene.PlayerShip; obj.Object.RenderComponent.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; obj.Object.RenderComponent.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; obj.Object.RenderComponent.NoFog = kv.Value.NoFog; ((ModelRenderer)obj.Object.RenderComponent).LightGroup = kv.Value.LightGroup; obj.Entity = kv.Value; Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.SetLocalTransform((kv.Value.RotationMatrix ?? Matrix4x4.Identity) * Matrix4x4.CreateTranslation(transform)); obj.HpMount = Cutscene.PlayerShip.GetHardpoint("HpMount"); Cutscene.World.AddObject(obj.Object); Objects.Add(kv.Key, obj); continue; } var template = kv.Value.Template; string replacement; if (Cutscene.Substitutions != null && Cutscene.Substitutions.TryGetValue(kv.Value.Template, out replacement)) { template = replacement; } var resman = Cutscene.Game.GetService <ResourceManager>(); var gameData = Cutscene.GameData; if (spawnObjects && kv.Value.Type == EntityTypes.Compound) { bool getHpMount = false; //Fetch model IDrawable drawable = null; float[] lodranges = null; if (!string.IsNullOrEmpty(template)) { switch (kv.Value.MeshCategory.ToLowerInvariant()) { case "solar": (drawable, lodranges) = gameData.GetSolar(template); break; case "ship": case "spaceship": getHpMount = true; var sh = gameData.GetShip(template); drawable = sh.ModelFile.LoadFile(resman); break; case "prop": drawable = gameData.GetProp(template); break; case "room": drawable = gameData.GetRoom(template); break; case "equipment cart": drawable = gameData.GetCart(template); break; case "equipment": var eq = gameData.GetEquipment(template); drawable = eq?.ModelFile.LoadFile(resman); break; case "asteroid": drawable = gameData.GetAsteroid(kv.Value.Template); break; default: throw new NotImplementedException("Mesh Category " + kv.Value.MeshCategory); } } else { FLLog.Warning("Thn", $"object '{kv.Value.Name}' has empty template, category " + $"'{kv.Value.MeshCategory}'"); } drawable?.Initialize(resman); if (kv.Value.UserFlag != 0) { //This is a starsphere Cutscene.AddStarsphere(drawable, obj); } else { obj.Object = new GameObject(drawable, Cutscene.Game.GetService <ResourceManager>(), true, false); obj.Object.Name = kv.Value.Name; obj.Object.PhysicsComponent = null; //Jitter seems to interfere with directly setting orientation if (getHpMount) { obj.HpMount = obj.Object.GetHardpoint("HpMount"); } var r = (ModelRenderer)obj.Object.RenderComponent; if (r != null) { r.LightGroup = kv.Value.LightGroup; r.LitDynamic = (kv.Value.ObjectFlags & ThnObjectFlags.LitDynamic) == ThnObjectFlags.LitDynamic; r.LitAmbient = (kv.Value.ObjectFlags & ThnObjectFlags.LitAmbient) == ThnObjectFlags.LitAmbient; //HIDDEN just seems to be an editor flag? //r.Hidden = (kv.Value.ObjectFlags & ThnObjectFlags.Hidden) == ThnObjectFlags.Hidden; r.NoFog = kv.Value.NoFog; r.LODRanges = lodranges; } } } else if (kv.Value.Type == EntityTypes.PSys) { var fx = gameData.GetEffect(kv.Value.Template); if (fx != null) { obj.Object = new GameObject(); obj.Object.RenderComponent = new ParticleEffectRenderer(fx.GetEffect(resman)) { Active = false }; } } else if (kv.Value.Type == EntityTypes.Scene) { if (kv.Value.DisplayText != null) { Cutscene.SetDisplayText(kv.Value.DisplayText); } var amb = kv.Value.Ambient.Value; if (amb.X == 0 && amb.Y == 0 && amb.Z == 0) { continue; } Cutscene.SetAmbient(amb); } else if (kv.Value.Type == EntityTypes.Light) { var lt = new DynamicLight(); lt.LightGroup = kv.Value.LightGroup; lt.Active = kv.Value.LightProps.On; lt.Light = kv.Value.LightProps.Render; obj.Light = lt; obj.LightDir = lt.Light.Direction; if (kv.Value.RotationMatrix.HasValue) { var m = kv.Value.RotationMatrix.Value; lt.Light.Direction = Vector3.TransformNormal(lt.Light.Direction, m); } if (Cutscene.Renderer != null) { Cutscene.Renderer.SystemLighting.Lights.Add(lt); } } else if (kv.Value.Type == EntityTypes.Camera) { obj.Camera = new ThnCameraTransform(); obj.Camera.Position = kv.Value.Position.Value; obj.Camera.Orientation = kv.Value.RotationMatrix ?? Matrix4x4.Identity; obj.Camera.FovH = kv.Value.FovH ?? obj.Camera.FovH; obj.Camera.AspectRatio = kv.Value.HVAspect ?? obj.Camera.AspectRatio; if (kv.Value.NearPlane != null) { obj.Camera.Znear = kv.Value.NearPlane.Value; } if (kv.Value.FarPlane != null) { obj.Camera.Zfar = kv.Value.FarPlane.Value; } } else if (kv.Value.Type == EntityTypes.Marker) { obj.Object = new GameObject(); obj.Object.Name = "Marker"; obj.Object.Nickname = ""; if (kv.Value.MainObject && Cutscene.MainObject != null) { obj.Object.Parent = Cutscene.MainObject; obj.Object.Components.Add(new DirtyTransformComponent(obj.Object)); obj.PosFromObject = true; } } else if (kv.Value.Type == EntityTypes.Deformable) { //TODO: Hacky with fidget/placement scripts if (string.IsNullOrEmpty(kv.Value.Actor) || !objects.ContainsKey(kv.Value.Actor)) { obj.Object = new GameObject(); gameData.GetCostume(template, out DfmFile body, out DfmFile head, out DfmFile leftHand, out DfmFile rightHand); var skel = new DfmSkeletonManager(body, head, leftHand, rightHand); obj.Object.RenderComponent = new CharacterRenderer(skel); var anmComponent = new AnimationComponent(obj.Object, gameData.GetCharacterAnimations()); obj.Object.AnimationComponent = anmComponent; obj.Object.Components.Add(anmComponent); } else { obj.Actor = kv.Value.Actor; if (Objects.TryGetValue(obj.Actor, out var act)) { act.Translate = obj.Translate; act.Rotate = obj.Rotate; act.Update(); } } } else if (kv.Value.Type == EntityTypes.Sound) { obj.Sound = new ThnSound(kv.Value.Template, Cutscene.Game.GetService <SoundManager>(), kv.Value.AudioProps, obj); obj.Sound.Spatial = (kv.Value.ObjectFlags & ThnObjectFlags.SoundSpatial) == ThnObjectFlags.SoundSpatial; } if (obj.Object != null) { if (!obj.PosFromObject) { Vector3 transform = kv.Value.Position ?? Vector3.Zero; obj.Object.SetLocalTransform((kv.Value.RotationMatrix ?? Matrix4x4.Identity) * Matrix4x4.CreateTranslation(transform)); } Cutscene.World.AddObject(obj.Object); } obj.Entity = kv.Value; Objects[kv.Key] = obj; } }