private void LoadEntitiesFromLump(Scene scene, LoadResult result, EntityLump entityLump, string layerName = null) { var childEntities = entityLump.GetChildEntityNames(); foreach (var childEntityName in childEntities) { var newResource = guiContext.LoadFileByAnyMeansNecessary(childEntityName + "_c"); if (newResource == null) { continue; } var childLump = (EntityLump)newResource.DataBlock; var childName = childLump.Data.GetProperty <string>("m_name"); LoadEntitiesFromLump(scene, result, childLump, childName); } var worldEntities = entityLump.GetEntities(); foreach (var entity in worldEntities) { var classname = entity.GetProperty <string>("classname"); if (classname == "info_world_layer") { var spawnflags = entity.GetProperty <uint>("spawnflags"); var layername = entity.GetProperty <string>("layername"); // Visible on spawn flag if ((spawnflags & 1) == 1) { result.DefaultEnabledLayers.Add(layername); } continue; } else if (classname == "skybox_reference") { var worldgroupid = entity.GetProperty <string>("worldgroupid"); var targetmapname = entity.GetProperty <string>("targetmapname"); var skyboxWorldPath = $"maps/{Path.GetFileNameWithoutExtension(targetmapname)}/world.vwrld_c"; var skyboxPackage = guiContext.LoadFileByAnyMeansNecessary(skyboxWorldPath); if (skyboxPackage != null) { result.Skybox = (World)skyboxPackage.DataBlock; } } var scale = entity.GetProperty <string>("scales"); var position = entity.GetProperty <string>("origin"); var angles = entity.GetProperty <string>("angles"); var model = entity.GetProperty <string>("model"); var skin = entity.GetProperty <string>("skin"); var colour = entity.GetProperty <byte[]>("rendercolor"); var particle = entity.GetProperty <string>("effect_name"); var animation = entity.GetProperty <string>("defaultanim"); if (scale == null || position == null || angles == null) { continue; } var isGlobalLight = classname == "env_global_light"; var isCamera = classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; var scaleMatrix = Matrix4x4.CreateScale(VectorExtensions.ParseVector(scale)); var positionVector = VectorExtensions.ParseVector(position); var positionMatrix = Matrix4x4.CreateTranslation(positionVector); var pitchYawRoll = VectorExtensions.ParseVector(angles); var rollMatrix = Matrix4x4.CreateRotationX(OpenTK.MathHelper.DegreesToRadians(pitchYawRoll.Z)); // Roll var pitchMatrix = Matrix4x4.CreateRotationY(OpenTK.MathHelper.DegreesToRadians(pitchYawRoll.X)); // Pitch var yawMatrix = Matrix4x4.CreateRotationZ(OpenTK.MathHelper.DegreesToRadians(pitchYawRoll.Y)); // Yaw var rotationMatrix = rollMatrix * pitchMatrix * yawMatrix; var transformationMatrix = scaleMatrix * rotationMatrix * positionMatrix; if (classname == "sky_camera") { result.SkyboxScale = entity.GetProperty <ulong>("scale"); result.SkyboxOrigin = positionVector; } if (particle != null) { var particleResource = guiContext.LoadFileByAnyMeansNecessary(particle + "_c"); if (particleResource != null) { var particleSystem = (ParticleSystem)particleResource.DataBlock; var origin = new Vector3(positionVector.X, positionVector.Y, positionVector.Z); try { var particleNode = new ParticleSceneNode(scene, particleSystem) { Transform = Matrix4x4.CreateTranslation(origin), LayerName = layerName, }; scene.Add(particleNode, true); } catch (Exception e) { Console.Error.WriteLine($"Failed to setup particle '{particle}': {e.Message}"); } } continue; } if (isCamera) { var name = entity.GetProperty <string>("targetname") ?? string.Empty; var cameraName = name == string.Empty ? classname : name; result.CameraMatrices.Add(cameraName, transformationMatrix); continue; } else if (isGlobalLight) { result.GlobalLightPosition = positionVector; continue; } else if (model == null) { continue; } var objColor = Vector4.One; // Parse colour if present if (colour != default && colour.Length == 4) { objColor.X = colour[0] / 255.0f; objColor.Y = colour[1] / 255.0f; objColor.Z = colour[2] / 255.0f; objColor.W = colour[3] / 255.0f; } var newEntity = guiContext.LoadFileByAnyMeansNecessary(model + "_c"); if (newEntity == null) { var errorModelResource = guiContext.LoadFileByAnyMeansNecessary("models/dev/error.vmdl_c"); if (errorModelResource != null) { var errorModel = new ModelSceneNode(scene, (Model)errorModelResource.DataBlock, skin, false) { Transform = transformationMatrix, LayerName = layerName, }; scene.Add(errorModel, false); } else { Console.WriteLine("Unable to load error.vmdl_c. Did you add \"core/pak_001.dir\" to your game paths?"); } continue; } var newModel = (Model)newEntity.DataBlock; var modelNode = new ModelSceneNode(scene, newModel, skin, false) { Transform = transformationMatrix, Tint = objColor, LayerName = layerName, }; if (animation != default) { modelNode.LoadAnimation(animation); // Load only this animation modelNode.SetAnimation(animation); } var bodyHash = EntityLumpKeyLookup.Get("body"); if (entity.Properties.ContainsKey(bodyHash)) { var groups = modelNode.GetMeshGroups(); var body = entity.Properties[bodyHash].Data; int bodyGroup = -1; if (body is ulong bodyGroupLong) { bodyGroup = (int)bodyGroupLong; } else if (body is string bodyGroupString) { int.TryParse(bodyGroupString, out bodyGroup); } modelNode.SetActiveMeshGroups(groups.Skip(bodyGroup).Take(1)); } scene.Add(modelNode, false); } }
private void LoadEntities(string entityName, Renderer.Renderer renderer, string path, Package package) { if (entityName == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(entityName + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + entityName + "_c"); return; } var entityLump = new EntityLump(newResource); var childEntities = entityLump.GetChildEntityNames(); foreach (var childEntityName in childEntities) { // TODO: Should be controlled in UI with world layers if (childEntityName.Contains("_destruction")) { continue; } LoadEntities(childEntityName, renderer, path, package); } var worldEntities = entityLump.GetEntities(); foreach (var entity in worldEntities) { var scale = string.Empty; var position = string.Empty; var angles = string.Empty; var model = string.Empty; var skin = string.Empty; var colour = new byte[0]; var classname = string.Empty; var name = string.Empty; foreach (var property in entity.Properties) { //metadata switch (property.MiscType) { case 3368008710: //World Model model = property.Data as string; break; case 3827302934: //Position position = property.Data as string; break; case 3130579663: //Angles angles = property.Data as string; break; case 432137260: //Scale scale = property.Data as string; break; case 2020856412: //Skin skin = property.Data as string; break; case 588463423: //Colour colour = property.Data as byte[]; break; case 3323665506: //Classname classname = property.Data as string; break; case 1094168427: name = property.Data as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } var isGlobalLight = classname == "env_global_light"; var isCamera = classname == "info_player_start" || classname == "worldspawn" || classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; if (!isGlobalLight && !isCamera && model == string.Empty) { continue; } var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionVector = ParseCoordinates(position); var positionMatrix = Matrix4.CreateTranslation(positionVector); var pitchYawRoll = ParseCoordinates(angles); var rollMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(pitchYawRoll.Z)); // Roll var pitchMatrix = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(pitchYawRoll.X)); // Pitch var yawMatrix = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(pitchYawRoll.Y)); // Yaw var rotationMatrix = rollMatrix * pitchMatrix * yawMatrix; var transformationMatrix = scaleMatrix * rotationMatrix * positionMatrix; if (isCamera) { if (classname == "worldspawn") { renderer.SetDefaultWorldCamera(positionVector); } else { renderer.AddCamera(name == string.Empty ? $"{classname} #{anonymousCameraCount++}" : name, transformationMatrix); } continue; } else if (isGlobalLight) { renderer.SetWorldGlobalLight(positionVector); // TODO: set light angle continue; } var objColor = Vector4.One; // Parse colour if present if (colour.Length == 4) { for (var i = 0; i < 4; i++) { objColor[i] = colour[i] / 255.0f; } } var newEntity = FileExtensions.LoadFileByAnyMeansNecessary(model + "_c", path, package); if (newEntity == null) { Console.WriteLine($"unable to load entity {model}_c"); continue; } var newModel = new Model(newEntity); var entityModel = new RenderModel(newModel); entityModel.LoadMeshes(renderer, path, transformationMatrix, objColor, package, skin); } }
private void LoadEntitiesFromLump(Scene scene, LoadResult result, EntityLump entityLump, string layerName = null) { var childEntities = entityLump.GetChildEntityNames(); foreach (var childEntityName in childEntities) { var newResource = guiContext.LoadFileByAnyMeansNecessary(childEntityName + "_c"); if (newResource == null) { continue; } var childLump = (EntityLump)newResource.DataBlock; var childName = childLump.Data.GetProperty <string>("m_name"); LoadEntitiesFromLump(scene, result, childLump, childName); } var worldEntities = entityLump.GetEntities(); foreach (var entity in worldEntities) { var classname = entity.GetProperty <string>("classname"); if (classname == "info_world_layer") { var spawnflags = entity.GetProperty <uint>("spawnflags"); var layername = entity.GetProperty <string>("layername"); // Visible on spawn flag if ((spawnflags & 1) == 1) { result.DefaultEnabledLayers.Add(layername); } continue; } else if (classname == "skybox_reference") { var worldgroupid = entity.GetProperty <string>("worldgroupid"); var targetmapname = entity.GetProperty <string>("targetmapname"); var skyboxWorldPath = $"maps/{Path.GetFileNameWithoutExtension(targetmapname)}/world.vwrld_c"; var skyboxPackage = guiContext.LoadFileByAnyMeansNecessary(skyboxWorldPath); if (skyboxPackage != null) { result.Skybox = (World)skyboxPackage.DataBlock; } } var scale = entity.GetProperty <string>("scales"); var position = entity.GetProperty <string>("origin"); var angles = entity.GetProperty <string>("angles"); var model = entity.GetProperty <string>("model"); var skin = entity.GetProperty <string>("skin"); var particle = entity.GetProperty <string>("effect_name"); //var animation = entity.GetProperty<string>("defaultanim"); string animation = null; if (scale == null || position == null || angles == null) { continue; } var isGlobalLight = classname == "env_global_light"; var isCamera = classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; var isTrigger = classname.Contains("trigger") || classname == "post_processing_volume"; var positionVector = EntityTransformHelper.ParseVector(position); var transformationMatrix = EntityTransformHelper.CalculateTransformationMatrix(entity); if (classname == "sky_camera") { result.SkyboxScale = entity.GetProperty <ulong>("scale"); result.SkyboxOrigin = positionVector; } if (particle != null) { var particleResource = guiContext.LoadFileByAnyMeansNecessary(particle + "_c"); if (particleResource != null) { var particleSystem = (ParticleSystem)particleResource.DataBlock; var origin = new Vector3(positionVector.X, positionVector.Y, positionVector.Z); try { var particleNode = new ParticleSceneNode(scene, particleSystem) { Transform = Matrix4x4.CreateTranslation(origin), LayerName = layerName, }; scene.Add(particleNode, true); } catch (Exception e) { Console.Error.WriteLine($"Failed to setup particle '{particle}': {e.Message}"); } } continue; } if (isCamera) { var name = entity.GetProperty <string>("targetname") ?? string.Empty; var cameraName = string.IsNullOrEmpty(name) ? classname : name; result.CameraMatrices.Add(cameraName, transformationMatrix); continue; } else if (isGlobalLight) { result.GlobalLightPosition = positionVector; continue; } else if (model == null) { continue; } var objColor = Vector4.One; // Parse colour if present var colour = entity.GetProperty("rendercolor"); // HL Alyx has an entity that puts rendercolor as a string instead of color255 // TODO: Make an enum for these types if (colour != default && colour.Type == 0x09) { var colourBytes = (byte[])colour.Data; objColor.X = colourBytes[0] / 255.0f; objColor.Y = colourBytes[1] / 255.0f; objColor.Z = colourBytes[2] / 255.0f; objColor.W = colourBytes[3] / 255.0f; } var newEntity = guiContext.LoadFileByAnyMeansNecessary(model + "_c"); if (newEntity == null) { var errorModelResource = guiContext.LoadFileByAnyMeansNecessary("models/dev/error.vmdl_c"); if (errorModelResource != null) { var errorModel = new ModelSceneNode(scene, (Model)errorModelResource.DataBlock, skin, false) { Transform = transformationMatrix, LayerName = layerName, }; scene.Add(errorModel, false); } continue; } var newModel = (Model)newEntity.DataBlock; var modelNode = new ModelSceneNode(scene, newModel, skin, false) { Transform = transformationMatrix, Tint = objColor, LayerName = layerName, }; if (animation != default) { modelNode.LoadAnimation(animation); // Load only this animation modelNode.SetAnimation(animation); } var bodyHash = StringToken.Get("body"); if (entity.Properties.ContainsKey(bodyHash)) { var groups = modelNode.GetMeshGroups(); var body = entity.Properties[bodyHash].Data; int bodyGroup = -1; if (body is ulong bodyGroupLong) { bodyGroup = (int)bodyGroupLong; } else if (body is string bodyGroupString) { if (!int.TryParse(bodyGroupString, out bodyGroup)) { bodyGroup = -1; } } modelNode.SetActiveMeshGroups(groups.Skip(bodyGroup).Take(1)); } scene.Add(modelNode, false); var phys = newModel.GetEmbeddedPhys(); if (phys == null) { var refPhysicsPaths = newModel.GetReferencedPhysNames(); if (refPhysicsPaths.Any()) { var newResource = guiContext.LoadFileByAnyMeansNecessary(refPhysicsPaths.First() + "_c"); if (newResource != null) { phys = (PhysAggregateData)newResource.DataBlock; } } } if (phys != null) { var physSceneNode = new PhysSceneNode(scene, phys) { Transform = transformationMatrix, IsTrigger = isTrigger, LayerName = layerName }; scene.Add(physSceneNode, false); } } }
private void LoadEntitiesFromLump(EntityLump entityLump) { var childEntities = entityLump.GetChildEntityNames(); foreach (var childEntityName in childEntities) { // TODO: Should be controlled in UI with world layers if (childEntityName.Contains("_destruction")) { continue; } var newResource = guiContext.LoadFileByAnyMeansNecessary(childEntityName + "_c"); if (newResource == null) { continue; } LoadEntitiesFromLump(new EntityLump(newResource)); } var worldEntities = entityLump.GetEntities(); foreach (var entity in worldEntities) { var scale = string.Empty; var position = string.Empty; var angles = string.Empty; string model = null; var skin = string.Empty; var colour = new byte[0]; var classname = string.Empty; string particle = null; string animation = null; foreach (var property in entity.Properties) { if (property.Key == EntityLumpKeyLookup.Get("model")) { model = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("origin")) { position = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("angles")) { angles = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("scales")) { scale = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("skin")) { skin = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("rendercolor")) { colour = property.Data as byte[]; } else if (property.Key == EntityLumpKeyLookup.Get("classname")) { classname = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("effect_name")) { particle = property.Data as string; } else if (property.Key == EntityLumpKeyLookup.Get("defaultanim")) { animation = property.Data as string; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } var isGlobalLight = classname == "env_global_light"; var isCamera = classname == "info_player_start" || classname == "worldspawn" || classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionVector = ParseCoordinates(position); var positionMatrix = Matrix4.CreateTranslation(positionVector); var pitchYawRoll = ParseCoordinates(angles); var rollMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(pitchYawRoll.Z)); // Roll var pitchMatrix = Matrix4.CreateRotationY(MathHelper.DegreesToRadians(pitchYawRoll.X)); // Pitch var yawMatrix = Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(pitchYawRoll.Y)); // Yaw var rotationMatrix = rollMatrix * pitchMatrix * yawMatrix; var transformationMatrix = scaleMatrix * rotationMatrix * positionMatrix; if (particle != null) { var particleResource = guiContext.LoadFileByAnyMeansNecessary(particle + "_c"); if (particleResource != null) { var particleSystem = new ParticleSystem(particleResource); var origin = new System.Numerics.Vector3(positionVector.X, positionVector.Y, positionVector.Z); //particleRenderers.Add(new ParticleRenderer.ParticleRenderer(particleSystem, guiContext, origin)); } continue; } if (isCamera) { if (classname == "worldspawn") { // TODO //glRenderControl.SetDefaultWorldCamera(positionVector); } else { // TODO //glRenderControl.AddCamera(name == string.Empty ? $"{classname} #{anonymousCameraCount++}" : name, transformationMatrix); } continue; } else if (isGlobalLight) { // TODO //glRenderControl.SetWorldGlobalLight(positionVector); // TODO: set light angle continue; } else if (model == null) { continue; } var objColor = Vector4.One; // Parse colour if present if (colour.Length == 4) { for (var i = 0; i < 4; i++) { objColor[i] = colour[i] / 255.0f; } } var newEntity = guiContext.LoadFileByAnyMeansNecessary(model + "_c"); if (newEntity == null) { continue; } var newModel = new Model(newEntity); var modelRenderer = new ModelRenderer(newModel, guiContext, skin, false); modelRenderer.SetMeshTransform(transformationMatrix); modelRenderer.SetTint(objColor); if (animation != default) { modelRenderer.LoadAnimation(animation); // Load only this animation modelRenderer.SetAnimation(animation); } worldOctree.Insert(modelRenderer); modelRenderers.Add(modelRenderer); BoundingBox = BoundingBox.IsZero ? modelRenderer.BoundingBox : BoundingBox.Union(modelRenderer.BoundingBox); } }