public LoadMeshes ( |
||
renderer | ||
path | string | |
transform | Matrix4 | |
tintColor | OpenTK.Vector4 | |
currentPackage | ValveResourceFormat.Package | |
skin | string | |
return | void |
private TabPage ProcessFile(string fileName, byte[] input, Package currentPackage) { var tab = new TabPage(); if (fileName.EndsWith(".vpk", StringComparison.Ordinal)) { var package = new Package(); try { if (input != null) { package.SetFileName(fileName); package.Read(new MemoryStream(input)); } else { package.Read(fileName); } } catch (InvalidDataException) when(input == null && Regex.IsMatch(fileName, @"_[0-9]{3}\.vpk$")) { // TODO: Update tab name fileName = $"{fileName.Substring(0, fileName.Length - 8)}_dir.vpk"; package.Read(fileName); } // create a TreeView with search capabilities, register its events, and add it to the tab var treeViewWithSearch = new TreeViewWithSearchResults(ImageList) { Dock = DockStyle.Fill, }; treeViewWithSearch.InitializeTreeViewFromPackage("treeViewVpk", package); treeViewWithSearch.TreeNodeMouseDoubleClick += VPK_OpenFile; treeViewWithSearch.TreeNodeMouseClick += VPK_OnClick; treeViewWithSearch.ListViewItemDoubleClick += VPK_OpenFile; treeViewWithSearch.ListViewItemRightClick += VPK_OnClick; tab.Controls.Add(treeViewWithSearch); // since we're in a separate thread, invoke to update the UI Invoke((MethodInvoker)(() => findToolStripButton.Enabled = true)); } else if (fileName.EndsWith(".vcs", StringComparison.Ordinal)) { var shader = new CompiledShader(); var buffer = new StringWriter(); var oldOut = Console.Out; Console.SetOut(buffer); if (input != null) { shader.Read(fileName, new MemoryStream(input)); } else { shader.Read(fileName); } Console.SetOut(oldOut); var control = new TextBox(); control.Font = new Font(FontFamily.GenericMonospace, control.Font.Size); control.Text = NormalizeLineEndings(buffer.ToString()); control.Dock = DockStyle.Fill; control.Multiline = true; control.ReadOnly = true; control.ScrollBars = ScrollBars.Both; tab.Controls.Add(control); } else { var resource = new Resource(); if (input != null) { resource.Read(new MemoryStream(input)); } else { resource.Read(fileName); } var resTabs = new TabControl { Dock = DockStyle.Fill, }; switch (resource.ResourceType) { case ResourceType.Texture: var tab2 = new TabPage("TEXTURE") { AutoScroll = true, }; try { var tex = (Texture)resource.Blocks[BlockType.DATA]; var control = new Forms.Texture { BackColor = Color.Black, }; control.SetImage(tex.GenerateBitmap().ToBitmap(), Path.GetFileNameWithoutExtension(fileName), tex.Width, tex.Height); tab2.Controls.Add(control); Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as an image", fileName, new ExportData { Resource = resource }); } catch (Exception e) { var control = new TextBox { Dock = DockStyle.Fill, Font = new Font(FontFamily.GenericMonospace, 8), Multiline = true, ReadOnly = true, Text = e.ToString(), }; tab2.Controls.Add(control); } resTabs.TabPages.Add(tab2); break; case ResourceType.Panorama: if (((Panorama)resource.Blocks[BlockType.DATA]).Names.Count > 0) { var nameTab = new TabPage("PANORAMA NAMES"); var nameControl = new DataGridView { Dock = DockStyle.Fill, AutoSize = true, ReadOnly = true, AllowUserToAddRows = false, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, DataSource = new BindingSource(new BindingList <Panorama.NameEntry>(((Panorama)resource.Blocks[BlockType.DATA]).Names), null), }; nameTab.Controls.Add(nameControl); resTabs.TabPages.Add(nameTab); } break; case ResourceType.PanoramaLayout: Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as XML", fileName, new ExportData { Resource = resource }); break; case ResourceType.PanoramaScript: Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as JS", fileName, new ExportData { Resource = resource }); break; case ResourceType.PanoramaStyle: Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as CSS", fileName, new ExportData { Resource = resource }); break; case ResourceType.Sound: var soundTab = new TabPage("SOUND"); var ap = new AudioPlayer(resource, soundTab); resTabs.TabPages.Add(soundTab); Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as {((Sound)resource.Blocks[BlockType.DATA]).Type}", fileName, new ExportData { Resource = resource }); break; case ResourceType.World: var world = new World(resource); var worldmv = new Renderer(mainTabs, fileName, currentPackage, RenderSubject.World); world.AddObjects(worldmv, fileName, currentPackage); var worldmeshTab = new TabPage("MAP"); var worldglControl = worldmv.CreateGL(); worldmeshTab.Controls.Add(worldglControl); resTabs.TabPages.Add(worldmeshTab); break; case ResourceType.WorldNode: var node = new WorldNode(resource); var nodemv = new Renderer(mainTabs, fileName, currentPackage); node.AddMeshes(nodemv, fileName, currentPackage); var nodemeshTab = new TabPage("MAP"); var nodeglControl = nodemv.CreateGL(); nodemeshTab.Controls.Add(nodeglControl); resTabs.TabPages.Add(nodemeshTab); break; case ResourceType.Model: // Create model var model = new Model(resource); // Create skeleton var skeleton = new Skeleton(resource); // Create tab var modelmeshTab = new TabPage("MESH"); var modelmv = new Renderer(mainTabs, fileName, currentPackage, RenderSubject.Model); model.LoadMeshes(modelmv, fileName, Matrix4.Identity, Vector4.One, currentPackage); // Add skeleton to renderer modelmv.SetSkeleton(skeleton); // Add animations if available var animGroupPaths = model.GetAnimationGroups(); foreach (var animGroupPath in animGroupPaths) { var animGroup = FileExtensions.LoadFileByAnyMeansNecessary(animGroupPath + "_c", fileName, currentPackage); modelmv.AddAnimations(AnimationGroupLoader.LoadAnimationGroup(animGroup, fileName)); } //Initialise OpenGL var modelglControl = modelmv.CreateGL(); modelmeshTab.Controls.Add(modelglControl); resTabs.TabPages.Add(modelmeshTab); break; case ResourceType.Mesh: if (!resource.Blocks.ContainsKey(BlockType.VBIB)) { Console.WriteLine("Old style model, no VBIB!"); break; } var meshTab = new TabPage("MESH"); var mv = new Renderer(mainTabs, fileName, currentPackage, RenderSubject.Model); Invoke(new ExportDel(AddToExport), $"Export {Path.GetFileName(fileName)} as OBJ", fileName, new ExportData { Resource = resource, Renderer = mv }); mv.AddMeshObject(new MeshObject { Resource = resource }); var glControl = mv.CreateGL(); meshTab.Controls.Add(glControl); resTabs.TabPages.Add(meshTab); break; } foreach (var block in resource.Blocks) { if (block.Key == BlockType.RERL) { var externalRefsTab = new TabPage("External Refs"); var externalRefs = new DataGridView { Dock = DockStyle.Fill, AutoGenerateColumns = true, AutoSize = true, ReadOnly = true, AllowUserToAddRows = false, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, DataSource = new BindingSource(new BindingList <ResourceExtRefList.ResourceReferenceInfo>(resource.ExternalReferences.ResourceRefInfoList), null), }; externalRefsTab.Controls.Add(externalRefs); resTabs.TabPages.Add(externalRefsTab); continue; } if (block.Key == BlockType.NTRO) { if (((ResourceIntrospectionManifest)block.Value).ReferencedStructs.Count > 0) { var externalRefsTab = new TabPage("Introspection Manifest: Structs"); var externalRefs = new DataGridView { Dock = DockStyle.Fill, AutoGenerateColumns = true, AutoSize = true, ReadOnly = true, AllowUserToAddRows = false, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, DataSource = new BindingSource(new BindingList <ResourceIntrospectionManifest.ResourceDiskStruct>(((ResourceIntrospectionManifest)block.Value).ReferencedStructs), null), }; externalRefsTab.Controls.Add(externalRefs); resTabs.TabPages.Add(externalRefsTab); } if (((ResourceIntrospectionManifest)block.Value).ReferencedEnums.Count > 0) { var externalRefsTab = new TabPage("Introspection Manifest: Enums"); var externalRefs2 = new DataGridView { Dock = DockStyle.Fill, AutoGenerateColumns = true, AutoSize = true, ReadOnly = true, AllowUserToAddRows = false, AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill, DataSource = new BindingSource(new BindingList <ResourceIntrospectionManifest.ResourceDiskEnum>(((ResourceIntrospectionManifest)block.Value).ReferencedEnums), null), }; externalRefsTab.Controls.Add(externalRefs2); resTabs.TabPages.Add(externalRefsTab); } //continue; } var tab2 = new TabPage(block.Key.ToString()); var control = new TextBox(); control.Font = new Font(FontFamily.GenericMonospace, control.Font.Size); try { if (block.Key == BlockType.DATA) { switch (resource.ResourceType) { case ResourceType.Particle: case ResourceType.Mesh: //Wrap it around a KV3File object to get the header. control.Text = NormalizeLineEndings(new KV3File(((BinaryKV3)block.Value).Data).ToString()); break; default: control.Text = NormalizeLineEndings(block.Value.ToString()); break; } } else { control.Text = NormalizeLineEndings(block.Value.ToString()); } } catch (Exception e) { control.Text = e.ToString(); } control.Dock = DockStyle.Fill; control.Multiline = true; control.ReadOnly = true; control.ScrollBars = ScrollBars.Both; tab2.Controls.Add(control); resTabs.TabPages.Add(tab2); } tab.Controls.Add(resTabs); } return(tab); }
internal void AddMeshes(Renderer.Renderer renderer, string path, Package package) { var data = Resource.Blocks[BlockType.DATA] as NTRO; // Output is WorldNode_t we need to iterate m_sceneObjects inside it. var sceneObjectLayerIndices = (NTROArray)data.Output["m_sceneObjectLayerIndices"]; var sceneObjects = (NTROArray)data.Output["m_sceneObjects"]; var i = 0; foreach (var entry in sceneObjects) { var layerIndice = ((NTROValue<byte>)sceneObjectLayerIndices[i]).Value; i++; // TODO: We want UI for this if (layerIndice == 2 || layerIndice == 4) { continue; } // sceneObject is SceneObject_t var sceneObject = ((NTROValue<NTROStruct>)entry).Value; var renderableModel = ((NTROValue<ResourceExtRefList.ResourceReferenceInfo>)sceneObject["m_renderableModel"]).Value; var transform = (NTROArray)sceneObject["m_vTransform"]; var matrix = default(Matrix4); // what is this for (var x = 0; x < 4; x++) { var a = ((NTROValue<Vector4>)transform[x]).Value; switch (x) { case 0: matrix.Column0 = new OpenTK.Vector4(a.X, a.Y, a.Z, a.W); break; case 1: matrix.Column1 = new OpenTK.Vector4(a.X, a.Y, a.Z, a.W); break; case 2: matrix.Column2 = new OpenTK.Vector4(a.X, a.Y, a.Z, a.W); break; case 3: matrix.Column3 = new OpenTK.Vector4(a.X, a.Y, a.Z, a.W); break; } } var tintColorWrongVector = ((NTROValue<Vector4>)sceneObject["m_vTintColor"]).Value; OpenTK.Vector4 tintColor; if (tintColorWrongVector.W == 0) { tintColor = OpenTK.Vector4.One; Console.WriteLine("Ignoring tintColor, it will f**k things up."); } else { tintColor = new OpenTK.Vector4(tintColorWrongVector.X, tintColorWrongVector.Y, tintColorWrongVector.Z, tintColorWrongVector.W); } if (renderableModel != null) { var newResource = FileExtensions.LoadFileByAnyMeansNecessary(renderableModel.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load model " + renderableModel.Name + "_c"); continue; } var modelEntry = new Model(newResource); modelEntry.LoadMeshes(renderer, path, matrix, tintColor, package); } var renderable = ((NTROValue<ResourceExtRefList.ResourceReferenceInfo>)sceneObject["m_renderable"]).Value; if (renderable != null) { var newResource = FileExtensions.LoadFileByAnyMeansNecessary(renderable.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load renderable " + renderable.Name + "_c"); continue; } renderer.AddMeshObject(new MeshObject { Resource = newResource, Transform = matrix, TintColor = tintColor }); } } }
private static void LoadEntities(NTROValue lump, Renderer.Renderer renderer, string path, Package package) { var reference = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; if (reference == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(reference.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + reference.Name + "_c"); return; } var entityLump = newResource.Blocks[BlockType.DATA] as EntityLump; var childLumps = (NTROArray)entityLump.Output["m_childLumps"]; foreach (var lump2 in childLumps) { var lol = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; // TODO: Should be controlled in UI with world layers if (lol.Name.Contains("_destruction")) { continue; } LoadEntities(lump2, renderer, path, package); } foreach (var entity in entityLump.Datas) { 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) { //metadata switch (property.Item2) { case 3368008710: //World Model model = property.Item3 as string; break; case 3827302934: //Position position = property.Item3 as string; break; case 3130579663: //Angles angles = property.Item3 as string; break; case 432137260: //Scale scale = property.Item3 as string; break; case 2020856412: //Skin skin = property.Item3 as string; break; case 588463423: //Colour colour = property.Item3 as byte[]; break; case 3323665506: //Classname classname = property.Item3 as string; break; case 1094168427: name = property.Item3 as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } var isCamera = classname == "info_player_start" || classname == "worldspawn" || classname == "sky_camera" || classname == "point_devshot_camera" || classname == "point_camera"; if (!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; } 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 entityModel = new Model(newEntity); entityModel.LoadMeshes(renderer, path, transformationMatrix, objColor, package, skin); } }
private static void LoadEntities(NTROValue lump, Renderer.Renderer renderer, string path, Package package) { var reference = ((NTROValue<ResourceExtRefList.ResourceReferenceInfo>)lump).Value; if (reference == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(reference.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + reference.Name + "_c"); return; } var entityLump = newResource.Blocks[BlockType.DATA] as EntityLump; var childLumps = (NTROArray)entityLump.Output["m_childLumps"]; foreach (var lump2 in childLumps) { var lol = ((NTROValue<ResourceExtRefList.ResourceReferenceInfo>)lump).Value; // TODO: Should be controlled in UI with world layers if (lol.Name.Contains("_destruction")) { continue; } LoadEntities(lump2, renderer, path, package); } foreach (var entity in entityLump.Datas) { 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) { //metadata switch (property.Item2) { case 3368008710: //World Model model = property.Item3 as string; break; case 3827302934: //Position position = property.Item3 as string; break; case 3130579663: //Angles angles = property.Item3 as string; break; case 432137260: //Scale scale = property.Item3 as string; break; case 2020856412: //Skin skin = property.Item3 as string; break; case 588463423: //Colour colour = property.Item3 as byte[]; break; case 3323665506: //Classname classname = property.Item3 as string; break; case 1094168427: name = property.Item3 as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } if (classname == "point_camera" || classname == "vr_teleport_marker" || model != string.Empty) { var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionMatrix = Matrix4.CreateTranslation(ParseCoordinates(position)); var rotationVector = ParseCoordinates(angles); var rotationMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(rotationVector.Z)); rotationMatrix *= Matrix4.CreateRotationY(MathHelper.DegreesToRadians(rotationVector.X)); rotationMatrix *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(rotationVector.Y)); var megaMatrix = scaleMatrix * rotationMatrix * positionMatrix; 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; } } //This model is hardcoded into the FGD if (classname == "vr_teleport_marker") { model = "models/effects/teleport/teleport_marker.vmdl"; } if (classname == "point_camera") { renderer.AddCamera(name == string.Empty ? $"Camera {anonymousCameraCount++}" : name, megaMatrix); } else { var newEntity = FileExtensions.LoadFileByAnyMeansNecessary(model + "_c", path, package); if (newEntity == null) { Console.WriteLine("unable to load entity " + model + "_c"); continue; } var entityModel = new Model(newEntity); entityModel.LoadMeshes(renderer, path, megaMatrix, objColor, package, skin); } } } }
internal void AddMeshes(Renderer.Renderer renderer, string path, Package package) { var data = Resource.Blocks[BlockType.DATA] as NTRO; var sceneObjectLayerIndices = (NTROArray)data.Output["m_sceneObjectLayerIndices"]; var sceneObjects = (NTROArray)data.Output["m_sceneObjects"]; var i = 0; // Output is WorldNode_t we need to iterate m_sceneObjects inside it foreach (var entry in sceneObjects) { var layerIndice = ((NTROValue <byte>)sceneObjectLayerIndices[i]).Value; i++; // TODO: We want UI for this if (layerIndice == 2 || layerIndice == 4) { continue; } // sceneObject is SceneObject_t var sceneObject = ((NTROValue <NTROStruct>)entry).Value; var renderableModel = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)sceneObject["m_renderableModel"]).Value; var transform = (NTROArray)sceneObject["m_vTransform"]; var matrix = default(Matrix4); // what is this for (var x = 0; x < 4; x++) { var a = ((NTROValue <System.Numerics.Vector4>)transform[x]).Value; switch (x) { case 0: matrix.Column0 = new Vector4(a.X, a.Y, a.Z, a.W); break; case 1: matrix.Column1 = new Vector4(a.X, a.Y, a.Z, a.W); break; case 2: matrix.Column2 = new Vector4(a.X, a.Y, a.Z, a.W); break; case 3: matrix.Column3 = new Vector4(a.X, a.Y, a.Z, a.W); break; } } var tintColorWrongVector = ((NTROValue <System.Numerics.Vector4>)sceneObject["m_vTintColor"]).Value; Vector4 tintColor; if (tintColorWrongVector.W == 0) { tintColor = Vector4.One; Console.WriteLine("Ignoring tintColor, it will f**k things up."); } else { tintColor = new Vector4(tintColorWrongVector.X, tintColorWrongVector.Y, tintColorWrongVector.Z, tintColorWrongVector.W); } if (renderableModel != null) { var newResource = FileExtensions.LoadFileByAnyMeansNecessary(renderableModel.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load model " + renderableModel.Name + "_c"); continue; } var modelEntry = new Model(newResource); modelEntry.LoadMeshes(renderer, path, matrix, tintColor, package); } var renderable = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)sceneObject["m_renderable"]).Value; if (renderable != null) { var newResource = FileExtensions.LoadFileByAnyMeansNecessary(renderable.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load renderable " + renderable.Name + "_c"); continue; } renderer.AddMeshObject(new MeshObject { Resource = newResource, Transform = matrix, TintColor = tintColor, }); } } }
private static void LoadEntities(NTROValue lump, Renderer.Renderer renderer, string path, Package package) { var reference = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; if (reference == null) { return; } var newResource = FileExtensions.LoadFileByAnyMeansNecessary(reference.Name + "_c", path, package); if (newResource == null) { Console.WriteLine("unable to load entity lump " + reference.Name + "_c"); return; } var entityLump = newResource.Blocks[BlockType.DATA] as EntityLump; var childLumps = (NTROArray)entityLump.Output["m_childLumps"]; foreach (var lump2 in childLumps) { var lol = ((NTROValue <ResourceExtRefList.ResourceReferenceInfo>)lump).Value; // TODO: Should be controlled in UI with world layers if (lol.Name.Contains("_destruction")) { continue; } LoadEntities(lump2, renderer, path, package); } foreach (var entity in entityLump.Datas) { 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) { //metadata switch (property.Item2) { case 3368008710: //World Model model = property.Item3 as string; break; case 3827302934: //Position position = property.Item3 as string; break; case 3130579663: //Angles angles = property.Item3 as string; break; case 432137260: //Scale scale = property.Item3 as string; break; case 2020856412: //Skin skin = property.Item3 as string; break; case 588463423: //Colour colour = property.Item3 as byte[]; break; case 3323665506: //Classname classname = property.Item3 as string; break; case 1094168427: name = property.Item3 as string; break; } } if (scale == string.Empty || position == string.Empty || angles == string.Empty) { continue; } if (classname == "point_camera" || classname == "vr_teleport_marker" || model != string.Empty) { var scaleMatrix = Matrix4.CreateScale(ParseCoordinates(scale)); var positionMatrix = Matrix4.CreateTranslation(ParseCoordinates(position)); var rotationVector = ParseCoordinates(angles); var rotationMatrix = Matrix4.CreateRotationX(MathHelper.DegreesToRadians(rotationVector.Z)); rotationMatrix *= Matrix4.CreateRotationY(MathHelper.DegreesToRadians(rotationVector.X)); rotationMatrix *= Matrix4.CreateRotationZ(MathHelper.DegreesToRadians(rotationVector.Y)); var megaMatrix = scaleMatrix * rotationMatrix * positionMatrix; 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; } } //This model is hardcoded into the FGD if (classname == "vr_teleport_marker") { model = "models/effects/teleport/teleport_marker.vmdl"; } if (classname == "point_camera") { renderer.AddCamera(name == string.Empty ? $"Camera {anonymousCameraCount++}" : name, megaMatrix); } else { var newEntity = FileExtensions.LoadFileByAnyMeansNecessary(model + "_c", path, package); if (newEntity == null) { Console.WriteLine("unable to load entity " + model + "_c"); continue; } var entityModel = new Model(newEntity); entityModel.LoadMeshes(renderer, path, megaMatrix, objColor, package, skin); } } } }