public static VMTFile LoadMaterial(String MaterialPath) { //Normalize path before do magic here //(Cuz some paths uses different separators or levels... so we normalize paths always) String TempPath = NormalizePath(MaterialPath, MaterialsSubFolder, MaterialsExtension[0], false); //If material exist in cache, return it if (MaterialCache.ContainsKey(TempPath)) { VMTFile VMTCache = MaterialCache[TempPath]; if (VMTCache.Material == null) { VMTCache.CreateMaterial(); } return(VMTCache); } //Else begin try load & parse material String FileName = TempPath + MaterialsExtension[0]; VMTFile VMTFile; using (Stream vmtStream = OpenFile(FileName)) { //If at least one material was not found, notify about that if (vmtStream == null) { Debug.LogWarning(FileName + " NOT FOUND!"); return(new VMTFile(null, FileName)); } //Else try load & parse material try { VMTFile = new VMTFile(vmtStream, FileName); if (VMTFile != null) { VMTFile.CreateMaterial(); } else { VMTFile = new VMTFile(null, FileName); } } catch (Exception ex) { //notify about error Debug.LogError(String.Format("{0}: {1}", TempPath, ex.Message)); return(new VMTFile(null, FileName)); } } //Add material to cache (to load faster than reparse material again, again and again...) MaterialCache.Add(TempPath, VMTFile); return(VMTFile); }
public Transform BuildModel(Boolean GenerateUV2 = false) { GameObject ModelObject = new GameObject(MDL_Header.Name); #region Bones Transform[] Bones = new Transform[MDL_Header.bone_count]; Dictionary <Int32, String> bonePathDict = new Dictionary <Int32, String>(); for (Int32 boneID = 0; boneID < MDL_Header.bone_count; boneID++) { GameObject BoneObject = new GameObject(MDL_BoneNames[boneID]); Bones[boneID] = BoneObject.transform;//MDL_Bones.Add(BoneObject.transform); Vector3 pos = MDL_StudioBones[boneID].pos * uLoader.UnitScale; Vector3 rot = MDL_StudioBones[boneID].rot * Mathf.Rad2Deg; //Invert x for convert right-handed to left-handed pos.x = -pos.x; if (MDL_StudioBones[boneID].parent >= 0) { Bones[boneID].parent = Bones[MDL_StudioBones[boneID].parent]; } else { //Swap Z & Y and invert Y (ex: X Z -Y) //only for parents, cuz parents used different order vectors float temp = pos.y; pos.y = pos.z; pos.z = -temp; Bones[boneID].parent = ModelObject.transform; } bonePathDict.Add(boneID, Bones[boneID].GetTransformPath(ModelObject.transform)); Bones[boneID].localPosition = pos; //Bones[i].localRotation = MDL_StudioBones[i].quat; if (MDL_StudioBones[boneID].parent == -1) { //Fix up parents Bones[boneID].localRotation = Quaternion.Euler(-90, 90, -90) * MathLibrary.AngleQuaternion(rot); } else { Bones[boneID].localRotation = MathLibrary.AngleQuaternion(rot); } } if (uLoader.DrawArmature) { MDLArmatureInfo DebugArmature = ModelObject.AddComponent <MDLArmatureInfo>(); DebugArmature.boneNodes = Bones; } #endregion #region Hitboxes if (MDL_Hitboxsets != null) { for (Int32 HitboxsetID = 0; HitboxsetID < MDL_Header.hitbox_count; HitboxsetID++) { for (Int32 HitboxID = 0; HitboxID < MDL_Hitboxsets[HitboxsetID].numhitboxes; HitboxID++) { mstudiobbox_t Hitbox = Hitboxes[HitboxsetID][HitboxID].BBox; BoxCollider BBox = new GameObject(String.Format("Hitbox_{0}", Bones[Hitbox.bone].name)).AddComponent <BoxCollider>(); BBox.size = MathLibrary.NegateX(Hitbox.bbmax - Hitbox.bbmin) * uLoader.UnitScale; BBox.center = (MathLibrary.NegateX(Hitbox.bbmax + Hitbox.bbmin) / 2) * uLoader.UnitScale; BBox.transform.parent = Bones[Hitbox.bone]; BBox.transform.localPosition = Vector3.zero; BBox.transform.localRotation = Quaternion.identity; //bbox.transform.tag = HitTagType(MDL_BBoxes[i].group); } } } #endregion #region BodyParts if (BuildMesh) { for (Int32 BodypartID = 0; BodypartID < MDL_Header.bodypart_count; BodypartID++) { StudioBodyPart BodyPart = MDL_Bodyparts[BodypartID]; for (Int32 ModelID = 0; ModelID < BodyPart.Models.Length; ModelID++) { StudioModel Model = BodyPart.Models[ModelID]; //Skip if model is blank if (Model.isBlank) { continue; } #region TODO: Remove this code after find way to strip unused vertexes for lod's (VTXStripGroup / VTXStrip) mstudiovertex_t[] Vertexes = Model.VerticesPerLod[0]; BoneWeight[] BoneWeight = new BoneWeight[Vertexes.Length]; Vector3[] Vertices = new Vector3[Vertexes.Length]; Vector3[] Normals = new Vector3[Vertexes.Length]; Vector2[] UvBuffer = new Vector2[Vertexes.Length]; for (Int32 i = 0; i < Vertexes.Length; i++) { Vertices[i] = MathLibrary.SwapZY(Vertexes[i].m_vecPosition * uLoader.UnitScale); Normals[i] = MathLibrary.SwapZY(Vertexes[i].m_vecNormal); Vector2 UV = Vertexes[i].m_vecTexCoord; if (uLoader.SaveAssetsToUnity && uLoader.ExportTextureAsPNG) { UV.y = -UV.y; } UvBuffer[i] = UV; BoneWeight[i] = GetBoneWeight(Vertexes[i].m_BoneWeights); } #endregion #region LOD Support Boolean DetailModeEnabled = uLoader.DetailMode == DetailMode.Lowest || uLoader.DetailMode == DetailMode.Low || uLoader.DetailMode == DetailMode.Medium || uLoader.DetailMode == DetailMode.High; Boolean LODExist = uLoader.EnableLODParsing && !DetailModeEnabled && Model.NumLODs > 1; Transform FirstLODObject = null; LODGroup LODGroup = null; LOD[] LODs = null; Single MaxSwitchPoint = 100; Int32 StartLODIndex = 0; if (LODExist) { LODs = new LOD[Model.NumLODs]; for (Int32 LODID = 1; LODID < 3; LODID++) { Int32 LastID = Model.NumLODs - LODID; ModelLODHeader_t LOD = Model.LODData[LastID]; //ignore $shadowlod if (LOD.switchPoint != -1) { if (LOD.switchPoint > 0) { MaxSwitchPoint = LOD.switchPoint; } //Set switchPoint from MaxSwitchPoint (if switchPoint is zero or negative) if (LODID == 2 || LOD.switchPoint == 0) { MaxSwitchPoint += MaxSwitchPoint * uLoader.NegativeAddLODPrecent; Model.LODData[LOD.switchPoint == 0 ? LastID : LastID + 1].switchPoint = MaxSwitchPoint; } // + Threshold used to avoid errors with LODGroup MaxSwitchPoint += uLoader.ThresholdMaxSwitch; break; } } } else { if (!uLoader.EnableLODParsing) { Model.NumLODs = 1; } } if (uLoader.EnableLODParsing && DetailModeEnabled) { StartLODIndex = uLoader.DetailMode == DetailMode.Lowest ? (Model.NumLODs - 1) : uLoader.DetailMode == DetailMode.Low ? (Int32)(Model.NumLODs / 1.5f) : uLoader.DetailMode == DetailMode.Medium ? (Model.NumLODs / 2) : (Int32)(Model.NumLODs / 2.5f); } #endregion #region Build Meshes for (Int32 LODID = StartLODIndex; LODID < Model.NumLODs; LODID++) { #region TODO: Uncomment after find way to strip unused vertexes for lod's (VTXStripGroup / VTXStrip) /*mstudiovertex_t[] Vertexes = Model.VerticesPerLod[LODID]; * * BoneWeight[] BoneWeight = new BoneWeight[Vertexes.Length]; * Vector3[] Vertices = new Vector3[Vertexes.Length]; * Vector3[] Normals = new Vector3[Vertexes.Length]; * Vector2[] UvBuffer = new Vector2[Vertexes.Length]; * * for (Int32 i = 0; i < Vertexes.Length; i++) * { * Vertices[i] = MathLibrary.SwapZY(Vertexes[i].m_vecPosition * uLoader.UnitScale); * Normals[i] = MathLibrary.SwapZY(Vertexes[i].m_vecNormal); * * Vector2 UV = Vertexes[i].m_vecTexCoord; * if (uLoader.SaveAssetsToUnity && uLoader.ExportTextureAsPNG) * UV.y = -UV.y; * * UvBuffer[i] = UV; * BoneWeight[i] = GetBoneWeight(Vertexes[i].m_BoneWeights); * }*/ #endregion #region LOD ModelLODHeader_t ModelLOD = Model.LODData[LODID]; if (LODExist) { if (ModelLOD.switchPoint == 0) { ModelLOD.switchPoint = MaxSwitchPoint; } else { ModelLOD.switchPoint = MaxSwitchPoint - ModelLOD.switchPoint; } ModelLOD.switchPoint -= ModelLOD.switchPoint * uLoader.SubstractLODPrecent; } #endregion #region Mesh //Create empty object for mesh GameObject MeshObject = new GameObject(Model.Model.Name); MeshObject.name += "_vLOD" + LODID; MeshObject.transform.parent = ModelObject.transform; //Create empty mesh and fill parsed data Mesh Mesh = new Mesh(); Mesh.name = MeshObject.name; Mesh.subMeshCount = Model.Model.nummeshes; Mesh.vertices = Vertices; //Make sure if mesh exist any vertexes if (Mesh.vertexCount <= 0) { Debug.LogWarning(String.Format("Mesh: \"{0}\" has no vertexes, skip building... (MDL Version: {1})", Mesh.name, MDL_Header.version)); continue; } Mesh.normals = Normals; Mesh.uv = UvBuffer; #endregion #region Renderers Renderer Renderer; //SkinnedMeshRenderer (Models with "animated" bones & skin data) if (!MDL_Header.flags.HasFlag(StudioHDRFlags.STUDIOHDR_FLAGS_STATIC_PROP)) { //Bind poses & bone weights SkinnedMeshRenderer SkinnedRenderer = MeshObject.AddComponent <SkinnedMeshRenderer>(); Renderer = SkinnedRenderer; Matrix4x4[] BindPoses = new Matrix4x4[Bones.Length]; for (Int32 i = 0; i < BindPoses.Length; i++) { BindPoses[i] = Bones[i].worldToLocalMatrix * MeshObject.transform.localToWorldMatrix; } Mesh.boneWeights = BoneWeight; Mesh.bindposes = BindPoses; SkinnedRenderer.sharedMesh = Mesh; SkinnedRenderer.bones = Bones; SkinnedRenderer.updateWhenOffscreen = true; } //MeshRenderer (models with "STUDIOHDR_FLAGS_STATIC_PROP" flag or with generic "static_prop" bone) else { MeshFilter MeshFilter = MeshObject.AddComponent <MeshFilter>(); Renderer = MeshObject.AddComponent <MeshRenderer>(); MeshFilter.sharedMesh = Mesh; } Renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.TwoSided; #endregion #region Debug Stuff #if UNITY_EDITOR DebugMaterial DebugMat = null; if (uLoader.DebugMaterials) { DebugMat = MeshObject.AddComponent <DebugMaterial>(); } #endif #endregion #region Triangles and Materials Material[] Materials = new Material[Mesh.subMeshCount]; for (Int32 MeshID = 0; MeshID < Model.Model.nummeshes; MeshID++) { //Set triangles per lod & submeshes Mesh.SetTriangles(Model.IndicesPerLod[LODID][MeshID], MeshID); //Find & parse materials String MaterialPath; Int32 LastDirID = MDL_TDirectories.Length - 1; for (Int32 DirID = 0; DirID < MDL_TDirectories.Length; DirID++) { MaterialPath = MDL_TDirectories[DirID] + MDL_Textures[Model.Meshes[MeshID].material]; //If material exist if (uResourceManager.ContainsFile(MaterialPath, uResourceManager.MaterialsSubFolder, uResourceManager.MaterialsExtension[0])) { VMTFile VMT = uResourceManager.LoadMaterial(MaterialPath); #region Debug Stuff #if UNITY_EDITOR if (uLoader.DebugMaterials) { DebugMat.Init(VMT); } #endif #endregion //Set material Materials[MeshID] = VMT.Material; break; } else if (DirID == LastDirID) { Materials[MeshID] = uResourceManager.LoadMaterial(String.Empty).Material; } } } Renderer.sharedMaterials = Materials; #endregion #region UV2 #if UNITY_EDITOR if (GenerateUV2) { UnityEditor.SerializedObject so = new UnityEditor.SerializedObject(Renderer); so.FindProperty("m_ScaleInLightmap").floatValue = uLoader.ModelsLightmapSize; so.ApplyModifiedProperties(); MeshObject.isStatic = GenerateUV2; uResourceManager.UV2GenerateCache.Add(Mesh); } #endif #endregion #region Set LOD's if (LODExist) { if (LODID == 0) { LODGroup = MeshObject.AddComponent <LODGroup>(); FirstLODObject = MeshObject.transform; } else if (FirstLODObject != null) { MeshObject.transform.parent = FirstLODObject; } LODs[LODID] = new LOD(ModelLOD.switchPoint / MaxSwitchPoint, new Renderer[] { Renderer }); } if (uLoader.EnableLODParsing && DetailModeEnabled) { break; } #endregion }//lod's per model //Init all parsed lod's into LODGroup if (LODGroup != null) { LODGroup.SetLODs(LODs); } #endregion } //models in bodypart } //Bodypart } #endregion #region Animations if (MDL_SeqDescriptions != null) { var AnimationComponent = ModelObject.AddComponent <Animation>(); for (Int32 seqID = 0; seqID < MDL_SeqDescriptions.Length; seqID++) { SeqInfo Sequence = Sequences[seqID]; AniInfo Animation = Sequence.ani; //Creating "AnimationCurve" for animation "paths" (aka frames where stored position (XYZ) & rotation (XYZW)) AnimationCurve[] posX = new AnimationCurve[MDL_Header.bone_count]; //X AnimationCurve[] posY = new AnimationCurve[MDL_Header.bone_count]; //Y AnimationCurve[] posZ = new AnimationCurve[MDL_Header.bone_count]; //Z AnimationCurve[] rotX = new AnimationCurve[MDL_Header.bone_count]; //X AnimationCurve[] rotY = new AnimationCurve[MDL_Header.bone_count]; //Y AnimationCurve[] rotZ = new AnimationCurve[MDL_Header.bone_count]; //Z AnimationCurve[] rotW = new AnimationCurve[MDL_Header.bone_count]; //W //Fill "AnimationCurve" arrays for (Int32 boneIndex = 0; boneIndex < MDL_Header.bone_count; boneIndex++) { posX[boneIndex] = new AnimationCurve(); posY[boneIndex] = new AnimationCurve(); posZ[boneIndex] = new AnimationCurve(); rotX[boneIndex] = new AnimationCurve(); rotY[boneIndex] = new AnimationCurve(); rotZ[boneIndex] = new AnimationCurve(); rotW[boneIndex] = new AnimationCurve(); } Int32 numFrames = Animation.studioAnim.numframes; //Used to avoid "Assertion failed" key count in Unity (if frames less than 2) if (numFrames < 2) { numFrames += 1; } //Create animation clip AnimationClip clip = new AnimationClip(); //Make it for legacy animation system (for now, but it possible to rework for Mecanim) clip.legacy = true; //Set animation clip name clip.name = Animation.name; //To avoid problems with "obfuscators" / "protectors" for models, make sure if model have name in sequence if (String.IsNullOrEmpty(clip.name)) { clip.name = "(empty)" + seqID; } for (Int32 frameIndex = 0; frameIndex < numFrames; frameIndex++) { //Get current frame from blend (meaning from "Animation") by index //AnimationFrame frame = Animation.Frames[frameIndex]; //Set keys (position / rotation) from current frame for (Int32 boneIndex = 0; boneIndex < Bones.Length; boneIndex++) { posX[boneIndex].AddKey(Animation.PosX[frameIndex][boneIndex]); posY[boneIndex].AddKey(Animation.PosY[frameIndex][boneIndex]); posZ[boneIndex].AddKey(Animation.PosZ[frameIndex][boneIndex]); rotX[boneIndex].AddKey(Animation.RotX[frameIndex][boneIndex]); rotY[boneIndex].AddKey(Animation.RotY[frameIndex][boneIndex]); rotZ[boneIndex].AddKey(Animation.RotZ[frameIndex][boneIndex]); rotW[boneIndex].AddKey(Animation.RotW[frameIndex][boneIndex]); //Set default pose from the first animation if (seqID == 0 && frameIndex == 0) { Bones[boneIndex].localPosition = new Vector3 ( Animation.PosX[0][boneIndex].value, Animation.PosY[0][boneIndex].value, Animation.PosZ[0][boneIndex].value ); Bones[boneIndex].localRotation = new Quaternion ( Animation.RotX[0][boneIndex].value, Animation.RotY[0][boneIndex].value, Animation.RotZ[0][boneIndex].value, Animation.RotW[0][boneIndex].value ); } } } //Apply animation paths (Position / Rotation) to clip for (Int32 boneIndex = 0; boneIndex < MDL_Header.bone_count; boneIndex++) { clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.x", posX[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.y", posY[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.z", posZ[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.x", rotX[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.y", rotY[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.z", rotZ[boneIndex]); clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.w", rotW[boneIndex]); } if (Animation.studioAnim.fps > 0.0f) { clip.frameRate = Animation.studioAnim.fps; } //This ensures a smooth interpolation (corrects the problem of "jitter" after 180~270 degrees rotation path) //can be "comment" if have idea how to replace this clip.EnsureQuaternionContinuity(); AnimationComponent.AddClip(clip, clip.name); } } #endregion //If model has compiled flag "$staticprop" //then rotate this model by 90 degrees (Y) //https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/public/studio.h#L1965 //Big thanks for this tip: //ShadelessFox //REDxEYE if (MDL_Header.flags.HasFlag(StudioHDRFlags.STUDIOHDR_FLAGS_STATIC_PROP)) { ModelObject.transform.eulerAngles = new Vector3(0, 90, 0); } return(ModelObject.transform); }
public static VMTFile ParseVMTFile(string name) { VMTFile material = new VMTFile(); string path = ""; if (name.StartsWith("/")) { name = name.Replace("/", ""); } if (name.Contains("materials/")) { name = name.Replace("materials/", ""); } if (name.Contains(".vmt")) { name = name.Replace(".vmt", ""); } path = ResourceManager.GetPath("materials/" + name + ".vmt"); if (path == null) { Debug.Log("materials/" + name + ".vmt: Not Found"); return(null); } string[] file = File.ReadAllLines(path); string[] temp = null; string line = null; int depth = 0; Dictionary <string, string> parameters = new Dictionary <string, string> (); string block = null; for (int i = 0; i < file.Length; i++) { line = file[i].Trim().Trim('\t'); if (string.IsNullOrEmpty(line) || line.StartsWith("//")) { continue; } if (line.StartsWith("{")) { depth++; continue; } if (depth == 0) { material.shader = line.Trim('"').ToLower(); } else if (depth == 1) { if (line.StartsWith("}")) { depth--; if (depth == 0) { break; } } else { if (line.Split(new char[] { ' ', '\t' }).Length < 2) { block = line.Trim('"').ToLower(); //Debug.Log("Start block "+block); //Debug.Log ("Line is short "+line); } else { temp = line.Trim().Split(new char[] { ' ', '\t' }, 2); if (temp.Length < 2) { Debug.Log(path + " " + line); } if (!parameters.ContainsKey(temp[0].Trim('"').ToLower())) { parameters.Add(temp[0].Trim('"').ToLower(), temp[1].Trim().Trim('"')); } } } } else if (depth == 2) { if (line.StartsWith("}")) { depth--; if (depth == 0) { break; } } else { if (line.Split(new char[] { ' ', '\t' }).Length < 2) { //Debug.Log ("Line is short "+line); } else { if (block == "insert") { temp = line.Trim().Split(new char[] { ' ', '\t' }, 2); if (temp.Length < 2) { Debug.Log(path + " " + line); } if (!parameters.ContainsKey(temp[0].Trim('"').ToLower())) { parameters.Add(temp[0].Trim('"').ToLower(), temp[1].Trim().Trim('"')); } else { parameters[temp[0].Trim('"').ToLower()] = temp[1].Trim().Trim('"'); } } } } } if (line.StartsWith("}")) { depth--; if (depth == 0) { break; } } } if (material.shader == "patch") { if (parameters.ContainsKey("include")) { //Debug.Log (name+ " include "+parameters["include"].ToLower()); debug material = ParseVMTFile(parameters["include"].ToLower()); //return ParseVMTFile(parameters["include"].ToLower()); if (material == null) { Debug.LogError("Include \"" + parameters["include"].ToLower() + "\" from material \"" + name + "\" missing"); return(null); } } else { Debug.LogWarning("Shader is patch but has no parameter include " + path); for (int i = 0; i < parameters.Keys.ToArray().Length; i++) { Debug.Log(parameters.Keys.ToArray()[i]); } return(null); } } /*if (parameters.ContainsKey("$basetexturetransform")) * { * //file[file.FindIndex (n => n.ToLower ().Contains ("$basetexturetransform"))]=""; * }*/ if (parameters.ContainsKey("$basetexture")) { material.basetexture = parameters["$basetexture"]; } else { //if(material.shader!="patch") // Debug.Log ("File "+name+".vmt with shader"+material.shader+" dont contains texture name"); if (parameters.ContainsKey("%tooltexture")) { //Debug.Log ("Split strings count: "+temp.Length); material.basetexture = parameters["%tooltexture"]; } else if (parameters.ContainsKey("$iris")) { material.basetexture = parameters["$iris"]; } //else // material.basetexture = null; } if (parameters.ContainsKey("$basetexture2")) { material.basetexture2 = parameters["$basetexture2"]; } if (parameters.ContainsKey("$bumpmap")) { material.dudvmap = parameters["$bumpmap"]; } if (parameters.ContainsKey("$surfaceprop")) { material.surfaceprop = parameters["$surfaceprop"]; } if (parameters.ContainsKey("alphatest")) { if (parameters["alphatest"] == "1") { material.alphatest = true; } } if (parameters.ContainsKey("$alphatest")) { if (parameters["$alphatest"] == "1") { material.alphatest = true; } } if (parameters.ContainsKey("$selfillum")) { if (parameters["$selfillum"] == "1") { material.selfillum = true; } } if (parameters.ContainsKey("$translucent")) { if (parameters["$translucent"] == "1") { material.translucent = true; } } if (parameters.ContainsKey("$additive")) { if (parameters["$additive"] == "1") { material.additive = true; } } if (parameters.ContainsKey("$dudvmap")) { material.dudvmap = parameters["$dudvmap"]; } if (parameters.ContainsKey("$normalmap")) { material.dudvmap = parameters["$normalmap"]; } return(material); }
public static void Configure(this Transform transform, List <String> Data) { //return; String Classname = Data[Data.FindIndex(n => n == "classname") + 1], Targetname = Data[Data.FindIndex(n => n == "targetname") + 1]; transform.name = Classname; //ResourceManager.LoadModel("editor/axis_helper").SetParent(transform, false); Int32 OriginIndex = Data.FindIndex(n => n == "origin"); if (OriginIndex != -1) { //Old but gold String[] origin = Data[OriginIndex + 1].Split(' '); while (origin.Length != 3) { Int32 TempIndex = OriginIndex + 1; origin = Data[Data.FindIndex(TempIndex, n => n == "origin") + 1].Split(' '); } //Old but gold transform.position = new Vector3(-origin[1].ToSingle(), origin[2].ToSingle(), origin[0].ToSingle()) * uLoader.UnitScale; } Int32 AnglesIndex = Data.FindIndex(n => n == "angles"); if (AnglesIndex != -1) { Vector3 EulerAngles = Data[AnglesIndex + 1].ToVector3(); EulerAngles = new Vector3(EulerAngles.x, -EulerAngles.y, -EulerAngles.z); if (Classname.StartsWith("light", StringComparison.Ordinal)) { EulerAngles.x = -EulerAngles.x; } Int32 PitchIndex = Data.FindIndex(n => n == "pitch"); //Lights if (PitchIndex != -1) { EulerAngles.x = -Data[PitchIndex + 1].ToSingle(); } transform.eulerAngles = EulerAngles; } if (Classname.Contains("trigger")) { for (Int32 i = 0; i < transform.childCount; i++) { GameObject Child = transform.GetChild(i).gameObject; Child.SetActive(false); Child.AddComponent <BoxCollider>().isTrigger = true; } } #if UNITY_EDITOR if (Classname.Equals("env_sprite")) { //TODO: fix scale LensFlare lensFlare = transform.gameObject.AddComponent <LensFlare>(); if (VBSPFile.GlowFlare == null) { String path = UnityEditor.AssetDatabase.GUIDToAssetPath(UnityEditor.AssetDatabase.FindAssets("Glow t:Flare")[0]); VBSPFile.GlowFlare = UnityEditor.AssetDatabase.LoadAssetAtPath <Flare>(path); } lensFlare.flare = VBSPFile.GlowFlare; lensFlare.brightness = Data[Data.FindIndex(n => n == "scale") + 1].ToSingle(); lensFlare.fadeSpeed = Data[Data.FindIndex(n => n == "GlowProxySize") + 1].ToSingle(); lensFlare.color = Data[Data.FindIndex(n => n == "rendercolor") + 1].ToColor32(); return; } #endif /*if (Classname.Equals("point_viewcontrol")) * { * transform.gameObject.AddComponent<point_viewcontrol>().Start(); * }*/ //3D Skybox if (uLoader.Use3DSkybox && Classname.Equals("sky_camera")) { //Setup 3DSkybox Camera playerCamera = new GameObject("CameraPlayer").AddComponent <Camera>(); Camera skyCamera = transform.gameObject.AddComponent <Camera>(); CameraFly camFly = playerCamera.gameObject.AddComponent <CameraFly>(); camFly.skyScale = Data[Data.FindIndex(n => n == "scale") + 1].ToSingle(); camFly.offset3DSky = transform.position; camFly.skyCamera = skyCamera.transform; playerCamera.depth = -1; playerCamera.clearFlags = CameraClearFlags.Depth; skyCamera.depth = -2; skyCamera.clearFlags = CameraClearFlags.Skybox; //Setup 3DSkybox return; } //3D Skybox //Lights //shadow_control used to change parameters of dynamic shadows on the map: direction, color, length. if (Classname.Equals("shadow_control")) { //It can be integrated for Unity? //String[] color = Data[Data.FindIndex(n => n == "color") + 1].Split(' '); //RenderSettings.subtractiveShadowColor = new Color32(Byte.Parse(color[0]), Byte.Parse(color[1]), Byte.Parse(color[2]), 255); RenderSettings.ambientGroundColor = Data[Data.FindIndex(n => n == "color") + 1].ToColor(); //Set light direction by shadow_control if (VBSPFile.LightEnvironment != null) { if ((VBSPFile.LightEnvironment.rotation == Quaternion.identity) && !uLoader.IgnoreShadowControl) { VBSPFile.LightEnvironment.rotation = transform.rotation; } UpdateEquatorColor(); } return; } //Lights parsing if (!uLoader.UseWorldLights && Classname.Contains("light") && !Classname.StartsWith("point")) { Color ambientLight; if (Classname.Equals("light_environment")) { if (VBSPFile.LightEnvironment != null) { return; } VBSPFile.LightEnvironment = transform; //TODO: Correct parse ambient color String _ambient = Data[Data.FindIndex(n => n == "_ambient") + 1]; ambientLight = _ambient.ToColor(); RenderSettings.ambientLight = ambientLight; //Set light direction by shadow_control if (VBSPFile.ShadowControl != null) { if (!uLoader.IgnoreShadowControl && transform.rotation == Quaternion.identity) { transform.rotation = VBSPFile.ShadowControl.rotation; } UpdateEquatorColor(); } } if (uLoader.ParseLights) { Light Light = transform.gameObject.AddComponent <Light>(); if (Classname.Equals("light_spot")) { Light.type = LightType.Spot; } else if (Classname.Equals("light_environment")) { Light.type = LightType.Directional; } Vector4 _lightColor = Data[Data.FindIndex(n => n == "_light") + 1].ToColorVec(); Single intensity = _lightColor.w; Single m_Attenuation0 = 0; Single m_Attenuation1 = 0; Single m_Attenuation2 = 0; Light.color = new Color(_lightColor.x / 255, _lightColor.y / 255, _lightColor.z / 255, 255); Single LightRadius = 256; if (Light.type == LightType.Spot || Light.type == LightType.Point) { if (Light.type == LightType.Spot) { //Single inner_cone = Converters.ToSingle(Data[Data.FindIndex(n => n == "_cone2") + 1]); Single cone = Data[Data.FindIndex(n => n == "_cone") + 1].ToSingle() * 2; //radius -= inner_cone / cone; Light.spotAngle = Mathf.Clamp(cone, 0, 179); } Single _distance = Data[Data.FindIndex(n => n == "_distance") + 1].ToInt32(); if (_distance != 0) { LightRadius = _distance; intensity *= 1.5f; } else { Single _fifty_percent_distance = Data[Data.FindIndex(n => n == "_fifty_percent_distance") + 1].ToSingle(); Boolean isFifty = _fifty_percent_distance != 0; if (isFifty) { //New light style Single _zero_percent_distance = Data[Data.FindIndex(n => n == "_zero_percent_distance") + 1].ToSingle(); if (_zero_percent_distance < _fifty_percent_distance) { // !!warning in lib code???!!! Debug.LogWarningFormat("light has _fifty_percent_distance of {0} but no zero_percent_distance", _fifty_percent_distance); _zero_percent_distance = 2.0f * _fifty_percent_distance; } Single a = 0, b = 1, c = 0; if (!MathLibrary.SolveInverseQuadraticMonotonic(0, 1.0f, _fifty_percent_distance, 2.0f, _zero_percent_distance, 256.0f, ref a, ref b, ref c)) { Debug.LogWarningFormat("can't solve quadratic for light {0} {1}", _fifty_percent_distance, _zero_percent_distance); } Single v50 = c + _fifty_percent_distance * (b + _fifty_percent_distance * a); Single scale = 2.0f / v50; a *= scale; b *= scale; c *= scale; m_Attenuation2 = a; m_Attenuation1 = b; m_Attenuation0 = c; } else { //Old light style Single constant_attn = Data[Data.FindIndex(n => n == "_constant_attn") + 1].ToSingle(); Single linear_attn = Data[Data.FindIndex(n => n == "_linear_attn") + 1].ToSingle(); Single quadratic_attn = Data[Data.FindIndex(n => n == "_quadratic_attn") + 1].ToSingle(); // old-style manually typed quadrtiac coefficients if (quadratic_attn < 0.001) { quadratic_attn = 0; } if (linear_attn < 0.001) { linear_attn = 0; } if (constant_attn < 0.001) { constant_attn = 0; } if ((constant_attn < 0.001) && (linear_attn < 0.001) && (quadratic_attn < 0.001)) { constant_attn = 1; } m_Attenuation2 = quadratic_attn; m_Attenuation1 = linear_attn; m_Attenuation0 = constant_attn; } // FALLBACK: older lights use this if (m_Attenuation2 == 0.0f) { if (m_Attenuation1 == 0.0f) { // Infinite, but we're not going to draw it as such LightRadius = 2000; } else { LightRadius = (intensity / 0.03f - m_Attenuation0) / m_Attenuation1; } } else { Single a = m_Attenuation2; Single b = m_Attenuation1; Single c = m_Attenuation0 - intensity / 0.03f; Single discrim = b * b - 4 * a * c; if (discrim < 0.0f) { // Infinite, but we're not going to draw it as such LightRadius = 2000; } else { LightRadius = (-b + Mathf.Sqrt(discrim)) / (2.0f * a); if (LightRadius < 0) { LightRadius = 0; } //DeadZoneLuna //TODO: Find the best way to fix that //DeadZoneLuna if (isFifty) { //TODO: WHY? LightRadius /= 10; } else { //TODO: Not enough intensity? LightRadius *= 10; } } } } Light.range = (LightRadius * uLoader.UnitScale); } Light.intensity = (intensity / 255f) * 1.75f; #if UNITY_EDITOR Light.lightmapBakeType = LightmapBakeType.Baked; #endif if (uLoader.UseDynamicLight) { Light.shadows = LightShadows.Soft; if (Light.type == LightType.Directional) { Light.shadowBias = 0.1f; Light.shadowNormalBias = 0; } else { Light.shadowBias = 0.01f; } } } return; } //Lights #region Counter-Strike entities test /*if (Classname.Equals("info_player_terrorist")) * { * //Placeholder model (can be removed if needed) * ResourceManager.LoadModel("player/t_phoenix").SetParent(transform, false); * } * * //Counter-Strike CT spawn point * if (Classname.Equals("info_player_counterterrorist")) * { * //Placeholder model (can be removed if needed) * ResourceManager.LoadModel("player/ct_urban").SetParent(transform, false); * } * * //Default spawn point * if (Classname.Equals("info_player_start")) * { * //Placeholder model (can be removed if needed) * ResourceManager.LoadModel("editor/playerstart").SetParent(transform, false); * } * * //weapon spawn point * if (Classname.Contains("weapon_")) * { * //Placeholder model (can be removed if needed) * ResourceManager.LoadModel("weapons/w_rif_ak47").SetParent(transform, false); * } * * //hostage spawn point * if (Classname.Equals("hostage_entity")) * { * String[] hostages = * { * "characters/hostage_01", * "characters/hostage_02", * "characters/hostage_03", * "characters/hostage_04" * }; * * ResourceManager.LoadModel(hostages[UnityEngine.Random.Range(0, hostages.Length)]).SetParent(transform, false); * }*/ #endregion Int32 RenderModeIndex = Data.FindIndex(n => n == "rendermode"); if (RenderModeIndex != -1) { if (Data[RenderModeIndex + 1] == "10") { for (Int32 i = 0; i < transform.childCount; i++) { GameObject Child = transform.GetChild(i).gameObject; Child.GetComponent <Renderer>().enabled = false; } } } if (Classname.Contains("prop_") || Classname.Contains("npc_"))// || Classname.Equals("asw_door")) { string ModelName = Data[Data.FindIndex(n => n == "model") + 1]; if (!string.IsNullOrEmpty(ModelName)) { uResourceManager.LoadModel(ModelName, uLoader.LoadAnims, uLoader.UseHitboxesOnModel).SetParent(transform, false); return; } return; } if (uLoader.ParseDecals && Classname.Equals("infodecal")) { String DecalName = Data[Data.FindIndex(n => n == "texture") + 1]; VMTFile DecalMaterial = uResourceManager.LoadMaterial(DecalName); Single DecalScale = DecalMaterial.GetSingle("$decalscale"); if (DecalScale <= 0) { DecalScale = 1f; } Int32 DecalWidth = DecalMaterial.Material.mainTexture.width; //X Int32 DecalHeight = DecalMaterial.Material.mainTexture.height; //Y Sprite DecalTexture = Sprite.Create((Texture2D)DecalMaterial.Material.mainTexture, new Rect(0, 0, DecalWidth, DecalHeight), Vector2.zero); Decal DecalBuilder = transform.gameObject.AddComponent <Decal>(); #if UNITY_EDITOR if (uLoader.DebugMaterials) { transform.gameObject.AddComponent <DebugMaterial>().Init(DecalMaterial); } #endif DecalBuilder.SetDirection(); DecalBuilder.MaxAngle = 87.5f; DecalBuilder.Offset = 0.001f; DecalBuilder.Sprite = DecalTexture; DecalBuilder.Material = DecalMaterial.Material; DecalBuilder.Material.SetTextureScale("_MainTex", new Vector2(-1, 1)); Single ScaleX = (DecalWidth * DecalScale) * uLoader.UnitScale; Single ScaleY = (DecalHeight * DecalScale) * uLoader.UnitScale; Single DepthSize = ScaleX; if (ScaleY < DepthSize) { DepthSize = ScaleY; } transform.localScale = new Vector3(ScaleX, ScaleY, DepthSize); transform.position += new Vector3(0, 0, 0.001f); #if !UNITY_EDITOR DecalBuilder.BuildAndSetDirty(); #endif } }