private void RefreshTexStatus() { allTexStatus.Clear(); string[] arrStrPath = Directory.GetFiles(Application.dataPath + "/Resources/atlas/UI/", "*.png", SearchOption.AllDirectories); for (int i = 0; i < arrStrPath.Length; ++i) { string strTempPath = arrStrPath[i].Replace(@"\", "/"); strTempPath = strTempPath.Substring(strTempPath.IndexOf("Assets")); TextureImporter textureImporter = AssetImporter.GetAtPath(strTempPath) as TextureImporter; if (textureImporter != null) { TextureEditor.ETextureCompress f = TextureEditor.ETextureCompress.Compress; TextureEditor.ETextureSize s = TextureEditor.ETextureSize.Original; bool isAtlas = TextureEditor.IsAtlas(strTempPath); TextureEditor.GetTexFormat(isAtlas, textureImporter.userData, out f, out s); if (!TextureEditor.IsDefaultFormat(isAtlas, f, s)) { TexInfo tf = new TexInfo(); tf.path = strTempPath; tf.srcFormat = f; tf.alphaSize = s; tf.isAtlas = isAtlas; allTexStatus.Add(tf); } } } allTexStatus.Sort(CompareNewMsg); }
public bool Add(TexInfo info, bool isReplace = false) { if (info == null) { return(false); } if (string.IsNullOrEmpty(info.name)) { return(false); } var texMaps = GetOrCreateMaps(); if (texMaps.ContainsKey(info.name)) { if (isReplace) { texMaps[info.name] = info; return(true); } return(false); } texMaps.Add(info.name, info); return(true); }
void OnGUI() { if (_labelstyle == null) { _labelstyle = new GUIStyle(EditorStyles.boldLabel); _labelstyle.fontSize = 11; } if (_labelstyle_1 == null) { _labelstyle_1 = new GUIStyle(EditorStyles.boldLabel); _labelstyle_1.fontStyle = FontStyle.BoldAndItalic; _labelstyle_1.fontSize = 11; } EditorGUILayout.Space(); GUILayout.Label("UI Texture Stats:", _labelstyle); if (GUILayout.Button("SetDefault", GUILayout.MaxWidth(80))) { SetDefaultAlpha(); } EditorGUILayout.Space(); scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, false); for (int i = 0; i < allTexStatus.Count; ++i) { TexInfo tf = allTexStatus[i]; GUILayout.BeginHorizontal(); GUILayout.Label(tf.path); EditorGUILayout.EnumPopup("压缩", tf.srcFormat); EditorGUILayout.EnumPopup("Alpha缩放", tf.alphaSize); GUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); }
// The inspiration for this is the BSPSource source code. It's not a direct copy but does essentially // the same thing as the algorithm to "create a prism back", and isn't as neatly written. public static MAPBrush createBrushFromWind(Vector3D[] froms, Vector3D[] tos, string texture, string backtex, TexInfo scaling) { Vector3D[] planepts = new Vector3D[3]; MAPBrushSide[] sides = new MAPBrushSide[froms.Length + 2]; // Each edge, plus a front and back side planepts[0] = froms[0]; planepts[1] = tos[0]; planepts[2] = tos[1]; Plane plane = new Plane(planepts); Vector3D reverseNormal = plane.Normal; sides[0] = new MAPBrushSide(planepts, texture, scaling.SAxis.Point, scaling.SShift, scaling.TAxis.Point, scaling.TShift, 0, 1, 1, 0, "wld_lightmap", 16, 0); Vector3D[] backplanepts = new Vector3D[3]; backplanepts[0] = froms[0] - (reverseNormal); backplanepts[1] = tos[1] - (reverseNormal); backplanepts[2] = tos[0] - (reverseNormal); Plane backplane = new Plane(backplanepts); Vector3D[] backaxes = TexInfo.textureAxisFromPlane(backplane); sides[1] = new MAPBrushSide(backplane, backtex, backaxes[0].Point, 0, backaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); for (int i = 0; i < froms.Length; i++) { // each edge Vector3D[] sideplanepts = new Vector3D[3]; sideplanepts[0] = froms[i]; sideplanepts[1] = tos[i]; sideplanepts[2] = froms[i] + (reverseNormal); Plane sideplane = new Plane(sideplanepts); Vector3D[] sideaxes = TexInfo.textureAxisFromPlane(sideplane); sides[i + 2] = new MAPBrushSide(sideplane, backtex, sideaxes[0].Point, 0, sideaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); } return(new MAPBrush(sides, 0, 0, false)); }
private TexInfo CreateDefaultTexInfo() { TexInfo defaultTexInfo = new TexInfo(); defaultTexInfo.name = DEFAULT_KEY; var smr = gameObject.GetComponent <SkinnedMeshRenderer>(); if (smr != null) { Material[] materials = smr.sharedMaterials; if (materials != null) { MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock(); for (int i = 0; i < materials.Length; ++i) { materialPropertyBlock.Clear(); smr.GetPropertyBlock(materialPropertyBlock, i); defaultTexInfo.mainTex = materialPropertyBlock.GetTexture("_MainTex"); defaultTexInfo.flowTex = materialPropertyBlock.GetTexture("_FlowTex"); break; } } } return(defaultTexInfo); }
protected override void OnUpdate(DX11RenderContext context) { //Grab a temp target if enabled TexInfo ti = this.rtm.GetRenderTarget(context); if (ti.w != this.width || ti.h != this.height || !this.targets.ContainsKey(context) || this.invalidate || ti.format != this.format) { this.invalidate = false; this.width = ti.w; this.height = ti.h; this.format = ti.format; this.depthmanager.NeedReset = true; if (targets.ContainsKey(context)) { context.ResourcePool.Unlock(targets[context]); } if (targetresolve.ContainsKey(context)) { context.ResourcePool.Unlock(targetresolve[context]); } int aacount = Convert.ToInt32(this.FInAASamplesPerPixel[0].Name); int aaquality = 0; if (aacount > 1) { List <SampleDescription> sds = context.GetMultisampleFormatInfo(ti.format); int maxlevels = sds[sds.Count - 1].Count; if (aacount > maxlevels) { FHost.Log(TLogType.Warning, "Multisample count too high for this format, reverted to: " + maxlevels); aacount = maxlevels; } DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; DX11RenderTarget2D temptargetresolve = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(1, 0), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; targets[context] = temptarget; targetresolve[context] = temptargetresolve; this.FOutBuffers[0][context] = temptargetresolve; this.FOutAABuffers[0][context] = temptarget; } else { //Bind both texture as same output DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; targets[context] = temptarget; this.FOutBuffers[0][context] = temptarget; this.FOutAABuffers[0][context] = temptarget; } } }
private void FindTexs(string pathInfo) { m_FormatMap.Clear(); m_SizeMap.Clear(); m_TexMap.Clear(); m_TexMatMap.Clear(); m_TexInfo = null; m_TexMat = null; m_Tex = null; m_TotalSize = 0; m_TotalCount = 0; EditorUtility.UnloadUnusedAssetsImmediate(); string[] parsePath = pathInfo.Split('='); string paths = parsePath[0]; string findType = parsePath[1]; string scanMat = parsePath[2]; string[] pathList = paths.Split('|'); if (scanMat == "1") { for (int i = 0; i < pathList.Length; ++i) { string subPath = pathList[i]; FindMat(subPath); } } bool findTex = false; bool findDependencies = false; if (findType == "0") { findTex = true; } else if (findType == "1") { findDependencies = true; } else if (findType == "2") { findTex = true; findDependencies = true; } for (int i = 0; i < pathList.Length; ++i) { string subPath = pathList[i]; if (findTex) { ScanTex(subPath, "*.png"); ScanTex(subPath, "*.tga"); } if (findDependencies) { ScanPrefab(subPath); } } m_TexMap.Clear(); }
public Texture(byte[] data, mapType type) : base(data) { switch (type) { case mapType.TYPE_NIGHTFIRE: name = DataReader.readNullTerminatedString(new byte[] { data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63] }); break; case mapType.TYPE_QUAKE: name = DataReader.readNullTerminatedString(new byte[] { data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15] }); break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SOF: case mapType.TYPE_DAIKATANA: texAxes = new TexInfo(DataReader.readPoint3F(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]), DataReader.readFloat(data[12], data[13], data[14], data[15]), DataReader.readPoint3F(data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27]), DataReader.readFloat(data[28], data[29], data[30], data[31]), -1, -1); flags = new byte[] { data[32], data[33], data[34], data[35] }; name = DataReader.readNullTerminatedString(new byte[] { data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], data[64], data[65], data[66], data[67], data[68], data[69], data[70], data[71] }); break; case mapType.TYPE_MOHAA: mask = DataReader.readNullTerminatedString(new byte[] { data[76], data[77], data[78], data[79], data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87], data[88], data[89], data[90], data[91], data[92], data[93], data[94], data[95], data[96], data[97], data[98], data[99], data[100], data[101], data[102], data[103], data[104], data[105], data[106], data[107], data[108], data[109], data[110], data[111], data[112], data[113], data[114], data[115], data[116], data[117], data[118], data[119], data[120], data[121], data[122], data[123], data[124], data[125], data[126], data[127], data[128], data[129], data[130], data[131], data[132], data[133], data[134], data[135], data[136], data[137], data[138], data[139] }); goto case mapType.TYPE_STEF2; case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: case mapType.TYPE_RAVEN: case mapType.TYPE_QUAKE3: case mapType.TYPE_COD: case mapType.TYPE_COD2: case mapType.TYPE_COD4: case mapType.TYPE_FAKK: name = DataReader.readNullTerminatedString(new byte[] { data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63] }); flags = new byte[] { data[64], data[65], data[66], data[67] }; contents = new byte[] { data[68], data[69], data[70], data[71] }; break; case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_TACTICALINTERVENTION: case mapType.TYPE_VINDICTUS: case mapType.TYPE_DMOMAM: name = DataReader.readString(data); break; case mapType.TYPE_SIN: texAxes = new TexInfo(DataReader.readPoint3F(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]), DataReader.readFloat(data[12], data[13], data[14], data[15]), DataReader.readPoint3F(data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27]), DataReader.readFloat(data[28], data[29], data[30], data[31]), -1, -1); flags = new byte[] { data[32], data[33], data[34], data[35] }; name = DataReader.readNullTerminatedString(new byte[] { data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], data[64], data[65], data[66], data[67], data[68], data[69], data[70], data[71], data[72], data[73], data[74], data[75], data[76], data[77], data[78], data[79], data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87], data[88], data[89], data[90], data[91], data[92], data[93], data[94], data[95], data[96], data[97], data[98], data[99] }); break; } }
private static void OnLoad(UnityEngine.Object asset, System.Object obj) { TempLoad tl = (TempLoad)obj; try { Texture2D tex = (Texture2D)asset; TexInfo texInfo = new TexInfo(); texInfo.tex = tex; texInfo.w = (short)tex.width; texInfo.h = (short)tex.height; tl.texInfo[tl.index] = texInfo; bool over = true; int i, count; TexInfo ti; for (i = 0, count = tl.texInfo.Length; i < count; i++) { ti = tl.texInfo[i]; if (ti == null) { over = false; break; } } tl.over = over; if (over) { if (tl.autoTemp) { PackCombineTexture(tl); } else { Texture2D texture = new Texture2D(1, 1); Rect[] rect = CreateTex(texture, tl.texInfo); ProcessCombine(tl, texture, rect); } } } catch (System.Exception e) { for (int i = 0; i < tl.meshList.Count; i++) { Object.Destroy(tl.meshList[i]); } if (tl.endCombine != null) { tl.endCombine(null, tl.plus, tl.sub, tl.endParam); } Debug.LogError("combine load e->" + asset.name + "^" + e.ToString()); } }
public Texture(byte[] data, mapType type):base(data) { switch (type) { case mapType.TYPE_NIGHTFIRE: name = DataReader.readNullTerminatedString(new byte[]{data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63]}); break; case mapType.TYPE_QUAKE: name = DataReader.readNullTerminatedString(new byte[]{data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]}); break; case mapType.TYPE_QUAKE2: case mapType.TYPE_SOF: case mapType.TYPE_DAIKATANA: texAxes = new TexInfo(DataReader.readPoint3F(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]), DataReader.readFloat(data[12], data[13], data[14], data[15]), DataReader.readPoint3F(data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27]), DataReader.readFloat(data[28], data[29], data[30], data[31]), - 1, - 1); flags = new byte[]{data[32], data[33], data[34], data[35]}; name = DataReader.readNullTerminatedString(new byte[]{data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], data[64], data[65], data[66], data[67], data[68], data[69], data[70], data[71]}); break; case mapType.TYPE_MOHAA: mask = DataReader.readNullTerminatedString(new byte[]{data[76], data[77], data[78], data[79], data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87], data[88], data[89], data[90], data[91], data[92], data[93], data[94], data[95], data[96], data[97], data[98], data[99], data[100], data[101], data[102], data[103], data[104], data[105], data[106], data[107], data[108], data[109], data[110], data[111], data[112], data[113], data[114], data[115], data[116], data[117], data[118], data[119], data[120], data[121], data[122], data[123], data[124], data[125], data[126], data[127], data[128], data[129], data[130], data[131], data[132], data[133], data[134], data[135], data[136], data[137], data[138], data[139]}); goto case mapType.TYPE_STEF2; case mapType.TYPE_STEF2: case mapType.TYPE_STEF2DEMO: case mapType.TYPE_RAVEN: case mapType.TYPE_QUAKE3: case mapType.TYPE_COD: case mapType.TYPE_COD2: case mapType.TYPE_COD4: case mapType.TYPE_FAKK: name = DataReader.readNullTerminatedString(new byte[]{data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], data[28], data[29], data[30], data[31], data[32], data[33], data[34], data[35], data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63]}); flags = new byte[]{data[64], data[65], data[66], data[67]}; contents = new byte[]{data[68], data[69], data[70], data[71]}; break; case mapType.TYPE_SOURCE17: case mapType.TYPE_SOURCE18: case mapType.TYPE_SOURCE19: case mapType.TYPE_SOURCE20: case mapType.TYPE_SOURCE21: case mapType.TYPE_SOURCE22: case mapType.TYPE_SOURCE23: case mapType.TYPE_SOURCE27: case mapType.TYPE_TACTICALINTERVENTION: case mapType.TYPE_VINDICTUS: case mapType.TYPE_DMOMAM: name = DataReader.readString(data); break; case mapType.TYPE_SIN: texAxes = new TexInfo(DataReader.readPoint3F(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10], data[11]), DataReader.readFloat(data[12], data[13], data[14], data[15]), DataReader.readPoint3F(data[16], data[17], data[18], data[19], data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27]), DataReader.readFloat(data[28], data[29], data[30], data[31]), - 1, - 1); flags = new byte[]{data[32], data[33], data[34], data[35]}; name = DataReader.readNullTerminatedString(new byte[]{data[36], data[37], data[38], data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47], data[48], data[49], data[50], data[51], data[52], data[53], data[54], data[55], data[56], data[57], data[58], data[59], data[60], data[61], data[62], data[63], data[64], data[65], data[66], data[67], data[68], data[69], data[70], data[71], data[72], data[73], data[74], data[75], data[76], data[77], data[78], data[79], data[80], data[81], data[82], data[83], data[84], data[85], data[86], data[87], data[88], data[89], data[90], data[91], data[92], data[93], data[94], data[95], data[96], data[97], data[98], data[99]}); break; } }
protected override void OnUpdate(DX11RenderContext context) { //Grab a temp target if enabled TexInfo ti = this.rtm.GetRenderTarget(context); if (ti.w != this.width || ti.h != this.height || !this.targets.ContainsKey(context) || this.FInAASamplesPerPixel.IsChanged) { this.width = ti.w; this.height = ti.h; this.depthmanager.NeedReset = true; if (targets.ContainsKey(context)) { context.ResourcePool.Unlock(targets[context]); } if (targetresolve.ContainsKey(context)) { context.ResourcePool.Unlock(targetresolve[context]); } int aacount = Convert.ToInt32(this.FInAASamplesPerPixel[0].Name); int aaquality = 0; if (aacount > 1) { DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; DX11RenderTarget2D temptargetresolve = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(1, 0), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; targets[context] = temptarget; targetresolve[context] = temptargetresolve; this.FOutBuffers[0][context] = temptargetresolve; this.FOutAABuffers[0][context] = temptarget; } else { //Bind both texture as same output DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0]).Element; targets[context] = temptarget; this.FOutBuffers[0][context] = temptarget; this.FOutAABuffers[0][context] = temptarget; } } }
private void LoadTextures(IEnumerable <string> matFilenames) { var textures = new Dictionary <string, Texture2D[]>(); foreach (var matFilename in matFilenames) { if (textures.ContainsKey(matFilename.ToLower())) { Debug.LogWarning("Texture " + matFilename + " defined twice."); continue; } var mat = new MAT(); var matPath = @"3do\mat\" + matFilename; if (!_gobManager.Exists(matPath)) { matPath = @"mat\" + matFilename; } mat.ParseMat(_cmp, _gobManager.GetStream(matPath)); textures.Add(matFilename.ToLower(), new[] { mat.Textures[0] }); } var rects = Atlas.PackTextures(textures.Values.SelectMany(x => x).ToArray(), 0); var rectsOffset = 0; foreach (var matFilename in textures.Keys) { var numTextures = textures[matFilename].Length; var subrects = new Rect[numTextures]; Array.Copy(rects, rectsOffset, subrects, 0, subrects.Length); var sizes = new List <Vector2>(); foreach (var texture2D in textures[matFilename]) { sizes.Add(new Vector2(texture2D.width, texture2D.height)); } _materialLookup[matFilename] = new TexInfo { Rects = subrects, Sizes = sizes.ToArray() }; rectsOffset += numTextures; } }
private Dictionary <string, TexInfo> GetOrCreateMaps() { if (m_texInfoMap == null) { m_texInfoMap = new Dictionary <string, TexInfo>(); if (texInfoList != null) { foreach (var texInfo in texInfoList) { if (!m_texInfoMap.ContainsKey(texInfo.name)) { m_texInfoMap.Add(texInfo.name, texInfo); } } } m_curTexInfo = CreateDefaultTexInfo(); m_texInfoMap.Add(m_curTexInfo.name, m_curTexInfo); } return(m_texInfoMap); }
public List <TexInfo> ReadTexInfo(BinaryReader reader, BspHeader header) { List <TexInfo> infos = new List <TexInfo>(); var entry = header.GetLump(Lumps.TEXTURES); int numInfos = entry.Length / 76; Debug.Log(numInfos + " Texture Infos"); reader.BaseStream.Seek(entry.Offset, SeekOrigin.Begin); for (int i = 0; i < numInfos; i++) { var info = new TexInfo(); float ux = reader.ReadSingle(); float uy = reader.ReadSingle(); float uz = reader.ReadSingle(); info.uAxis = new Vector3(-ux, uz, -uy); info.uOffset = reader.ReadSingle(); // * QUAKE_TO_UNITY_CONVERSION_SCALE; // * scale?? float vx = reader.ReadSingle(); float vy = reader.ReadSingle(); float vz = reader.ReadSingle(); info.vAxis = new Vector3(-vx, vz, -vy); info.vOffset = reader.ReadSingle(); // * QUAKE_TO_UNITY_CONVERSION_SCALE; // * scale?? info.flags = reader.ReadUInt32(); info.value = reader.ReadUInt32(); info.name = new string(reader.ReadChars(32)); int pos = info.name.IndexOf('\0'); if (pos >= 0) { info.name = info.name.Substring(0, pos); } info.nextTexInfo = reader.ReadUInt32(); infos.Add(info); } return(infos); }
public string Change(string name) { var texMaps = GetOrCreateMaps(); if (texMaps.ContainsKey(name)) { var oldTexInfo = m_curTexInfo; var newTexInfo = texMaps[name]; var smr = gameObject.GetComponent <SkinnedMeshRenderer>(); if (smr != null) { Material[] materials = smr.sharedMaterials; if (materials != null) { MaterialPropertyBlock materialPropertyBlock = new MaterialPropertyBlock(); for (int i = 0; i < materials.Length; i++) { materialPropertyBlock.Clear(); smr.GetPropertyBlock(materialPropertyBlock, i); materialPropertyBlock.SetTexture("_MainTex", newTexInfo.mainTex); if (newTexInfo.flowTex) { materialPropertyBlock.SetTexture("_FlowTex", newTexInfo.flowTex); } smr.SetPropertyBlock(materialPropertyBlock, i); } m_curTexInfo = newTexInfo; return(oldTexInfo.name); } } } return(m_curTexInfo.name); }
// METHODS // Attempt to turn the BSP into a .MAP file public virtual Entities decompile() { DecompilerThread.OnMessage(this, "Decompiling..."); // In the decompiler, it is not necessary to copy all entities to a new object, since // no writing is ever done back to the BSP file. mapFile = BSPObject.Entities; //int numAreaPortals=0; int numTotalItems = 0; int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count)/100); if(onePercent < 1) { onePercent = 1; } int originalNumEntities = BSPObject.Entities.Count; // Need to keep track of this in this algorithm, since I create more entities on the fly for (int i = 0; i < originalNumEntities; i++) { // For each entity //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]); // getModelNumber() returns 0 for worldspawn, the *# for brush based entities, and -1 for everything else int currentModel = mapFile[i].ModelNumber; if (currentModel > - 1) { // If this is still -1 then it's strictly a point-based entity. Move on to the next one. Leaf[] leaves = BSPObject.getLeavesInModel(currentModel); int numLeaves = leaves.Length; bool[] brushesUsed = new bool[BSPObject.Brushes.Count]; // Keep a list of brushes already in the model, since sometimes the leaves lump references one brush several times numBrshs = 0; // Reset the brush count for each entity for (int j = 0; j < numLeaves; j++) { // For each leaf in the bunch Leaf currentLeaf = leaves[j]; int firstMarkBrushIndex = currentLeaf.FirstMarkBrush; int numBrushIndices = currentLeaf.NumMarkBrushes; if (numBrushIndices > 0) { // A lot of leaves reference no brushes. If this is one, this iteration of the j loop is finished for (int k = 0; k < numBrushIndices; k++) { // For each brush referenced long currentBrushIndex = BSPObject.MarkBrushes[firstMarkBrushIndex + k]; if (!brushesUsed[(int) currentBrushIndex]) { // If the current brush has NOT been used in this entity //Console.Write("Brush " + numBrshs); brushesUsed[(int) currentBrushIndex] = true; Brush brush = BSPObject.Brushes[(int) currentBrushIndex]; decompileBrush(brush, i); // Decompile the brush numBrshs++; numTotalItems++; if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } } } } } numTotalItems++; // This entity if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } // Find displacement faces and generate brushes for them for (int i = 0; i < BSPObject.Faces.Count; i++) { Face face = BSPObject.Faces[i]; if (face.Displacement > - 1) { SourceDispInfo disp = BSPObject.DispInfos[face.Displacement]; TexInfo currentTexInfo; if (face.Texture > - 1) { currentTexInfo = BSPObject.TexInfo[face.Texture]; } else { Vector3D[] axes = TexInfo.textureAxisFromPlane(BSPObject.Planes[face.Plane]); currentTexInfo = new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip")); } SourceTexData currentTexData = BSPObject.TexDatas[currentTexInfo.Texture]; string texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]); double[] textureU = new double[3]; double[] textureV = new double[3]; // Get the lengths of the axis vectors double SAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.SAxis.X, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.TAxis.X, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. double texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. double texScaleV = (1 / TAxisLength); textureU[0] = ((double) currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double) currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double) currentTexInfo.SAxis.Z / SAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftU = (double) currentTexInfo.SShift; textureV[0] = ((double) currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double) currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double) currentTexInfo.TAxis.Z / TAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftV = (double) currentTexInfo.TShift; if (face.NumEdges != 4) { DecompilerThread.OnMessage(this, "Displacement face with " + face.NumEdges + " edges!"); } // Turn vertices and edges into arrays of vectors Vector3D[] froms = new Vector3D[face.NumEdges]; Vector3D[] tos = new Vector3D[face.NumEdges]; for (int j = 0; j < face.NumEdges; j++) { if (BSPObject.SurfEdges[face.FirstEdge + j] > 0) { froms[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].FirstVertex].Vector; tos[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].SecondVertex].Vector; } else { tos[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].FirstVertex].Vector; froms[j] = BSPObject.Vertices[BSPObject.Edges[(int) BSPObject.SurfEdges[face.FirstEdge + j] * (- 1)].SecondVertex].Vector; } } MAPBrush displacementBrush = MAPBrush.createBrushFromWind(froms, tos, texture, "TOOLS/TOOLSNODRAW", currentTexInfo); MAPDisplacement mapdisp = new MAPDisplacement(disp, BSPObject.DispVerts.getVertsInDisp(disp.DispVertStart, disp.Power)); displacementBrush[0].Displacement = mapdisp; mapFile[0].Brushes.Add(displacementBrush); } } for (int i = 0; i < BSPObject.StaticProps.Count; i++) { Entity newStaticProp = new Entity("prop_static"); SourceStaticProp currentProp = BSPObject.StaticProps[i]; newStaticProp["model"] = BSPObject.StaticProps.Dictionary[currentProp.DictionaryEntry]; newStaticProp["skin"] = currentProp.Skin + ""; newStaticProp["origin"] = currentProp.Origin.X + " " + currentProp.Origin.Y + " " + currentProp.Origin.Z; newStaticProp["angles"] = currentProp.Angles.X + " " + currentProp.Angles.Y + " " + currentProp.Angles.Z; newStaticProp["solid"] = currentProp.Solidity + ""; newStaticProp["fademindist"] = currentProp.MinFadeDist + ""; newStaticProp["fademaxdist"] = currentProp.MaxFadeDist + ""; newStaticProp["fadescale"] = currentProp.ForcedFadeScale + ""; if (currentProp.Targetname != null) { newStaticProp["targetname"] = currentProp.Targetname; } mapFile.Add(newStaticProp); } for (int i = 0; i < BSPObject.Cubemaps.Count; i++) { Entity newCubemap = new Entity("env_cubemap"); SourceCubemap currentCube = BSPObject.Cubemaps[i]; newCubemap["origin"] = currentCube.Origin.X + " " + currentCube.Origin.Y + " " + currentCube.Origin.Z; newCubemap["cubemapsize"] = currentCube.Size + ""; mapFile.Add(newCubemap); } if (!Settings.skipPlaneFlip) { DecompilerThread.OnMessage(this, "Num simple corrected brushes: " + numSimpleCorrects); DecompilerThread.OnMessage(this, "Num advanced corrected brushes: " + numAdvancedCorrects); DecompilerThread.OnMessage(this, "Num good brushes: " + numGoodBrushes); } parent.OnProgress(this, 1.0); return mapFile; }
// -decompileBrush38(Brush, int, boolean) // Decompiles the Brush and adds it to entitiy #currentEntity as .MAP data. private void decompileBrush(Brush brush, int currentEntity) { Vector3D origin = mapFile[currentEntity].Origin; int firstSide = brush.FirstSide; int numSides = brush.NumSides; MAPBrushSide[] brushSides = new MAPBrushSide[numSides]; bool isDetail = false; if (currentEntity == 0 && !Settings.noDetail && (brush.Contents[3] & ((sbyte) 1 << 3)) != 0) { isDetail = true; } MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail); if (currentEntity == 0 && !Settings.noWater && (brush.Contents[0] & ((sbyte) 1 << 5)) != 0) { mapBrush.Water = true; } //DecompilerThread.OnMessage(this, ": " + numSides + " sides, detail: " + isDetail); for (int i = 0; i < numSides; i++) { // For each side of the brush BrushSide currentSide = BSPObject.BrushSides[firstSide + i]; if (currentSide.isBevel() == 0) { // Bevel sides are evil Vector3D[] plane = new Vector3D[3]; // Three points define a plane. All I have to do is find three points on that plane. Plane currentPlane = BSPObject.Planes[currentSide.Plane]; // To find those three points, I must extrapolate from planes until I find a way to associate faces with brushes bool isDuplicate = false; /* TODO: We sure don't want duplicate planes (though this is already handled by the MAPBrush class). Make sure neither checked side is bevel. for(int j=i+1;j<numSides;j++) { // For each subsequent side of the brush if(currentPlane.equals(BSPObject.Planes.getPlane(BSPObject.getBrushSides()[firstSide+j).getPlane()))) { DecompilerThread.OnMessage(this, "WARNING: Duplicate planes in a brush, sides "+i+" and "+j,Settings.VERBOSITY_WARNINGS); isDuplicate=true; } }*/ if (!isDuplicate) { TexInfo currentTexInfo = null; string texture = "tools/toolsclip"; if (currentSide.Texture > - 1) { currentTexInfo = BSPObject.TexInfo[currentSide.Texture]; } else { int dataIndex = BSPObject.findTexDataWithTexture("tools/toolsclip"); if (dataIndex >= 0) { currentTexInfo = new TexInfo(new Vector3D(0, 0, 0), 0, new Vector3D(0, 0, 0), 0, 0, dataIndex); } } if (currentTexInfo != null) { SourceTexData currentTexData; if (currentTexInfo.Texture >= 0) { // I've only found one case where this is a problem: c2a3a in HL Source. Don't know why. currentTexData = BSPObject.TexDatas[currentTexInfo.Texture]; texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]); } else { texture = "tools/toolsskip"; } } double[] textureU = new double[3]; double[] textureV = new double[3]; double textureShiftU = 0; double textureShiftV = 0; double texScaleU = 1; double texScaleV = 1; // Get the lengths of the axis vectors if ((texture.Length > 6 && texture.Substring(0, (6) - (0)).ToUpper().Equals("tools/".ToUpper())) || currentTexInfo == null) { // Tools textured faces do not maintain their own texture axes. Therefore, an arbitrary axis is // used in the compiled map. When decompiled, these axes might smear the texture on the face. Fix that. Vector3D[] axes = TexInfo.textureAxisFromPlane(currentPlane); textureU = axes[0].Point; textureV = axes[1].Point; } else { double SAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.SAxis.X, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double) currentTexInfo.TAxis.X, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double) currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. texScaleV = (1 / TAxisLength); textureU[0] = ((double) currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double) currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double) currentTexInfo.SAxis.Z / SAxisLength); double originShiftU = (((double) currentTexInfo.SAxis.X / SAxisLength) * origin[X] + ((double) currentTexInfo.SAxis.Y / SAxisLength) * origin[Y] + ((double) currentTexInfo.SAxis.Z / SAxisLength) * origin[Z]) / texScaleU; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" textureShiftU = (double) currentTexInfo.SShift - originShiftU; textureV[0] = ((double) currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double) currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double) currentTexInfo.TAxis.Z / TAxisLength); double originShiftV = (((double) currentTexInfo.TAxis.X / TAxisLength) * origin[X] + ((double) currentTexInfo.TAxis.Y / TAxisLength) * origin[Y] + ((double) currentTexInfo.TAxis.Z / TAxisLength) * origin[Z]) / texScaleV; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" textureShiftV = (double) currentTexInfo.TShift - originShiftV; } float texRot = 0; // In compiled maps this is calculated into the U and V axes, so set it to 0 until I can figure out a good way to determine a better value. int flags = 0; // Set this to 0 until we can somehow associate faces with brushes string material = "wld_lightmap"; // Since materials are a NightFire only thing, set this to a good default double lgtScale = 16; // These values are impossible to get from a compiled map since they double lgtRot = 0; // are used by RAD for generating lightmaps, then are discarded, I believe. brushSides[i] = new MAPBrushSide(currentPlane, texture, textureU, textureShiftU, textureV, textureShiftV, texRot, texScaleU, texScaleV, flags, material, lgtScale, lgtRot); mapBrush.add(brushSides[i]); } } } if (!Settings.skipPlaneFlip) { if (mapBrush.hasBadSide()) { // If there's a side that might be backward if (mapBrush.hasGoodSide()) { // If there's a side that is forward mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush); numSimpleCorrects++; if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { // If no forward side exists try { mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush); numAdvancedCorrects++; } catch (System.ArithmeticException) { DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { numGoodBrushes++; } } else { if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } // This adds the brush we've been finding and creating to // the current entity as an attribute. The way I've coded // this whole program and the entities parser, this shouldn't // cause any issues at all. if (Settings.brushesToWorld) { mapBrush.Water = false; mapFile[0].Brushes.Add(mapBrush); } else { mapFile[currentEntity].Brushes.Add(mapBrush); } }
// The inspiration for this is the BSPSource source code. It's not a direct copy but does essentially // the same thing as the algorithm to "create a prism back", and isn't as neatly written. public static MAPBrush createBrushFromWind(Vector3D[] froms, Vector3D[] tos, string texture, string backtex, TexInfo scaling) { Vector3D[] planepts = new Vector3D[3]; MAPBrushSide[] sides = new MAPBrushSide[froms.Length + 2]; // Each edge, plus a front and back side planepts[0] = froms[0]; planepts[1] = tos[0]; planepts[2] = tos[1]; Plane plane = new Plane(planepts); Vector3D reverseNormal = plane.Normal; sides[0] = new MAPBrushSide(planepts, texture, scaling.SAxis.Point, scaling.SShift, scaling.TAxis.Point, scaling.TShift, 0, 1, 1, 0, "wld_lightmap", 16, 0); Vector3D[] backplanepts = new Vector3D[3]; backplanepts[0] = froms[0]-(reverseNormal); backplanepts[1] = tos[1]-(reverseNormal); backplanepts[2] = tos[0]-(reverseNormal); Plane backplane = new Plane(backplanepts); Vector3D[] backaxes = TexInfo.textureAxisFromPlane(backplane); sides[1] = new MAPBrushSide(backplane, backtex, backaxes[0].Point, 0, backaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); for (int i = 0; i < froms.Length; i++) { // each edge Vector3D[] sideplanepts = new Vector3D[3]; sideplanepts[0] = froms[i]; sideplanepts[1] = tos[i]; sideplanepts[2] = froms[i]+(reverseNormal); Plane sideplane = new Plane(sideplanepts); Vector3D[] sideaxes = TexInfo.textureAxisFromPlane(sideplane); sides[i + 2] = new MAPBrushSide(sideplane, backtex, sideaxes[0].Point, 0, sideaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0); } return new MAPBrush(sides, 0, 0, false); }
// -decompileBrush(Brush, int, boolean) // Decompiles the Brush and adds it to entitiy #currentEntity as .MAP data. private void decompileBrush(Brush brush, int currentEntity) { Vector3D origin = mapFile[currentEntity].Origin; int firstSide = brush.FirstSide; int numSides = brush.NumSides; MAPBrushSide[] brushSides = new MAPBrushSide[0]; bool isDetail = false; if (!Settings.noDetail && (brush.Contents[1] & ((sbyte)1 << 1)) != 0) { isDetail = true; } MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail); int numRealFaces = 0; Plane[] brushPlanes = new Plane[0]; //DecompilerThread.OnMessage(this, ": " + numSides + " sides"); if (mapFile[currentEntity]["classname"] == "func_water") { mapBrush.Water = true; } for (int l = 0; l < numSides; l++) { // For each side of the brush BrushSide currentSide = BSPObject.BrushSides[firstSide + l]; Face currentFace = BSPObject.Faces[currentSide.Face]; // To find those three points, I can use vertices referenced by faces. string texture = BSPObject.Textures[currentFace.Texture].Name; if ((currentFace.Flags & 0x00000100) == 0) { // Surfaceflags 512 + 256 + 32 are set only by the compiler, on faces that need to be thrown out. if (!texture.ToUpper().Equals("special/clip".ToUpper()) && !texture.ToUpper().Equals("special/playerclip".ToUpper()) && !texture.ToUpper().Equals("special/enemyclip".ToUpper())) { if (Settings.replaceWithNull && ((currentFace.Flags & 0x00000200) != 0) && !texture.ToUpper().Equals("special/trigger".ToUpper())) { texture = "special/null"; currentFace.Flags = 0; } } int firstVertex = currentFace.FirstVertex; int numVertices = currentFace.NumVertices; Plane currentPlane; try { // I've only ever come across this error once or twice, but something causes it very rarely currentPlane = BSPObject.Planes[currentSide.Plane]; } catch (System.IndexOutOfRangeException) { try { // So try to get the plane index from somewhere else currentPlane = BSPObject.Planes[currentFace.Plane]; } catch (System.IndexOutOfRangeException f) { // If that fails, BS something DecompilerThread.OnMessage(this, "WARNING: BSP has error, references nonexistant plane " + currentSide.Plane + ", bad side " + (l) + " of brush " + numBrshs + " Entity " + currentEntity); currentPlane = new Plane((double)1, (double)0, (double)0, (double)0); } } Vector3D[] triangle = new Vector3D[0]; // Three points define a plane. All I have to do is find three points on that plane. bool pointsWorked = false; if (numVertices != 0 && !Settings.planarDecomp) { // If the face actually references a set of vertices triangle = new Vector3D[3]; double currentHighest = 0.0; // Find the combination of three vertices which gives the greatest area for (int p1 = 0; p1 < numVertices - 2; p1++) { for (int p2 = p1 + 1; p2 < numVertices - 1; p2++) { for (int p3 = p2 + 1; p3 < numVertices; p3++) { double currentArea = Vector3D.SqrTriangleArea(BSPObject.Vertices[firstVertex + p1].Vector, BSPObject.Vertices[firstVertex + p2].Vector, BSPObject.Vertices[firstVertex + p3].Vector); if (currentArea > Settings.precision * Settings.precision * 4.0) // Three collinear points will generate an area of 0 or almost 0 { pointsWorked = true; if (currentArea > currentHighest) { currentHighest = currentArea; triangle[0] = BSPObject.Vertices[firstVertex + p1].Vector; triangle[1] = BSPObject.Vertices[firstVertex + p2].Vector; triangle[2] = BSPObject.Vertices[firstVertex + p3].Vector; } } } } } } double[] textureU = new double[3]; double[] textureV = new double[3]; TexInfo currentTexInfo = BSPObject.TexInfo[currentFace.TextureScale]; // Get the lengths of the axis vectors double SAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.SAxis.X, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.TAxis.X, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. double texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. double texScaleV = (1 / TAxisLength); textureU[0] = ((double)currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double)currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double)currentTexInfo.SAxis.Z / SAxisLength); double originShiftU = (textureU[0] * origin[X] + textureU[1] * origin[Y] + textureU[2] * origin[Z]) / texScaleU; double textureUhiftU = (double)currentTexInfo.SShift - originShiftU; textureV[0] = ((double)currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double)currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double)currentTexInfo.TAxis.Z / TAxisLength); double originShiftV = (textureV[0] * origin[X] + textureV[1] * origin[Y] + textureV[2] * origin[Z]) / texScaleV; double textureUhiftV = (double)currentTexInfo.TShift - originShiftV; float texRot = 0; // In compiled maps this is calculated into the U and V axes, so set it to 0 until I can figure out a good way to determine a better value. string material; try { material = BSPObject.Materials[currentFace.Material].Name; } catch (System.IndexOutOfRangeException) { // In case the BSP has some strange error making it reference nonexistant materials DecompilerThread.OnMessage(this, "WARNING: Map referenced nonexistant material #" + currentFace.Material + ", using wld_lightmap instead!"); material = "wld_lightmap"; } double lgtScale = 16; // These values are impossible to get from a compiled map since they double lgtRot = 0; // are used by RAD for generating lightmaps, then are discarded, I believe. MAPBrushSide[] newList = new MAPBrushSide[brushSides.Length + 1]; for (int i = 0; i < brushSides.Length; i++) { newList[i] = brushSides[i]; } if (Settings.noFaceFlags) { currentFace.Flags = 0; } if (pointsWorked) { newList[brushSides.Length] = new MAPBrushSide(currentPlane, triangle, texture, textureU, textureUhiftU, textureV, textureUhiftV, texRot, texScaleU, texScaleV, currentFace.Flags, material, lgtScale, lgtRot); } else { newList[brushSides.Length] = new MAPBrushSide(currentPlane, texture, textureU, textureUhiftU, textureV, textureUhiftV, texRot, texScaleU, texScaleV, currentFace.Flags, material, lgtScale, lgtRot); } brushSides = newList; numRealFaces++; } } for (int i = 0; i < brushSides.Length; i++) { mapBrush.add(brushSides[i]); } brushPlanes = new Plane[mapBrush.NumSides]; for (int i = 0; i < brushPlanes.Length; i++) { brushPlanes[i] = mapBrush[i].Plane; } if (!Settings.skipPlaneFlip) { if (mapBrush.hasBadSide()) { // If there's a side that might be backward if (mapBrush.hasGoodSide()) { // If there's a side that is forward mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush); numSimpleCorrects++; if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { // If no forward side exists try { mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush); numAdvancedCorrects++; } catch (System.ArithmeticException) { DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { numGoodBrushes++; } } else { if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } // This adds the brush we've been finding and creating to // the current entity as an attribute. The way I've coded // this whole program and the entities parser, this shouldn't // cause any issues at all. if (Settings.brushesToWorld) { mapBrush.Water = false; mapFile[0].Brushes.Add(mapBrush); } else { mapFile[currentEntity].Brushes.Add(mapBrush); } }
private string brushSideToString(MAPBrushSide inputData) { try { Vector3D[] triangle = inputData.Triangle; string texture = inputData.Texture; Vector3D textureS = inputData.TextureS; Vector3D textureT = inputData.TextureT; double textureShiftS = inputData.TextureShiftS; double textureShiftT = inputData.TextureShiftT; float texRot = inputData.TexRot; double texScaleX = inputData.TexScaleX; double texScaleY = inputData.TexScaleY; int flags = inputData.Flags; string material = inputData.Material; double lgtScale = inputData.LgtScale; double lgtRot = inputData.LgtRot; if (Double.IsInfinity(texScaleX) || Double.IsNaN(texScaleX)) { texScaleX = 1; } if (Double.IsInfinity(texScaleY) || Double.IsNaN(texScaleY)) { texScaleY = 1; } if (Double.IsInfinity(textureShiftS) || Double.IsNaN(textureShiftS)) { textureShiftS = 0; } if (Double.IsInfinity(textureShiftT) || Double.IsNaN(textureShiftT)) { textureShiftT = 0; } if (Double.IsInfinity(textureS.X) || Double.IsNaN(textureS.X) || Double.IsInfinity(textureS.Y) || Double.IsNaN(textureS.Y) || Double.IsInfinity(textureS.Z) || Double.IsNaN(textureS.Z)) { textureS = TexInfo.textureAxisFromPlane(inputData.Plane)[0]; } if (Double.IsInfinity(textureT.X) || Double.IsNaN(textureT.X) || Double.IsInfinity(textureT.Y) || Double.IsNaN(textureT.Y) || Double.IsInfinity(textureT.Z) || Double.IsNaN(textureT.Z)) { textureT = TexInfo.textureAxisFromPlane(inputData.Plane)[1]; } if (Settings.roundNums) { return("( " + Math.Round(triangle[0].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[0].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[0].Z, 6, MidpointRounding.AwayFromZero) + " ) " + "( " + Math.Round(triangle[1].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[1].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[1].Z, 6, MidpointRounding.AwayFromZero) + " ) " + "( " + Math.Round(triangle[2].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[2].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[2].Z, 6, MidpointRounding.AwayFromZero) + " ) " + texture + " [ " + Math.Round(textureS.X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureS.Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureS.Z, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureShiftS, MidpointRounding.AwayFromZero) + " ]" + " [ " + Math.Round(textureT.X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureT.Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureT.Z, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureShiftT, MidpointRounding.AwayFromZero) + " ] " + Math.Round(texRot, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(texScaleX, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(texScaleY, 4, MidpointRounding.AwayFromZero) + " " + flags + " " + material + " [ " + Math.Round(lgtScale, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(lgtRot, 4, MidpointRounding.AwayFromZero) + " ]"); } else { return("( " + triangle[0].X + " " + triangle[0].Y + " " + triangle[0].Z + " ) " + "( " + triangle[1].X + " " + triangle[1].Y + " " + triangle[1].Z + " ) " + "( " + triangle[2].X + " " + triangle[2].Y + " " + triangle[2].Z + " ) " + texture + " [ " + textureS.X + " " + textureS.Y + " " + textureS.Z + " " + textureShiftS + " ]" + " [ " + textureT.X + " " + textureT.Y + " " + textureT.Z + " " + textureShiftT + " ] " + texRot + " " + texScaleX + " " + texScaleY + " " + flags + " " + material + " [ " + lgtScale + " " + lgtRot + " ]"); } } catch (System.NullReferenceException) { Console.WriteLine("WARNING: Side with bad data! Not exported!"); return(""); } }
private string brushSideToString(MAPBrushSide inputData, bool isDetail) { try { Vector3D[] triangle = inputData.Triangle; string texture = inputData.Texture; Vector3D textureS = inputData.TextureS; Vector3D textureT = inputData.TextureT; double textureShiftS = inputData.TextureShiftS; double textureShiftT = inputData.TextureShiftT; float texRot = inputData.TexRot; double texScaleX = inputData.TexScaleX; double texScaleY = inputData.TexScaleY; int flags = inputData.Flags; string material = inputData.Material; double lgtScale = inputData.LgtScale; double lgtRot = inputData.LgtRot; string temp = ""; // Correct textures here try { if (texture.Substring(0, (9) - (0)).ToUpper().Equals("textures/".ToUpper())) { texture = texture.Substring(9); } } catch (System.ArgumentOutOfRangeException) { ; } if (BSPVersion == mapType.TYPE_NIGHTFIRE || BSPVersion == mapType.TYPE_DOOM || BSPVersion == mapType.TYPE_HEXEN) { if (texture.ToUpper().Equals("special/nodraw".ToUpper()) || texture.ToUpper().Equals("special/null".ToUpper())) { texture = "common/nodraw"; } else { if (texture.ToUpper().Equals("special/clip".ToUpper())) { texture = "common/clip"; } else { if (texture.ToUpper().Equals("special/sky".ToUpper())) { texture = "common/skyportal"; } else { if (texture.ToUpper().Equals("special/trigger".ToUpper())) { texture = "common/trigger"; } else { if (texture.ToUpper().Equals("special/playerclip".ToUpper())) { texture = "common/playerclip"; } else { if (texture.ToUpper().Equals("special/npcclip".ToUpper()) || texture.ToUpper().Equals("special/enemyclip".ToUpper())) { texture = "common/tankclip"; } } } } } } } else { if (BSPVersion == mapType.TYPE_QUAKE2) { try { if (texture.ToUpper().Equals("special/hint".ToUpper())) { texture = "common/hint"; } else { if (texture.ToUpper().Equals("special/skip".ToUpper())) { texture = "common/skip"; } else { if (texture.ToUpper().Equals("special/sky".ToUpper())) { texture = "common/skyportal"; } else { if (texture.Substring(texture.Length - 8).ToUpper().Equals("/trigger".ToUpper())) { texture = "common/trigger"; } else { if (texture.Substring(texture.Length - 5).ToUpper().Equals("/clip".ToUpper())) { texture = "common/clip"; } } } } } } catch (System.ArgumentOutOfRangeException e) { ; } } else { if (BSPVersion == mapType.TYPE_SOURCE17 || BSPVersion == mapType.TYPE_SOURCE18 || BSPVersion == mapType.TYPE_SOURCE19 || BSPVersion == mapType.TYPE_SOURCE20 || BSPVersion == mapType.TYPE_SOURCE21 || BSPVersion == mapType.TYPE_SOURCE22 || BSPVersion == mapType.TYPE_SOURCE23 || BSPVersion == mapType.TYPE_DMOMAM || BSPVersion == mapType.TYPE_VINDICTUS || BSPVersion == mapType.TYPE_TACTICALINTERVENTION) { try { if (texture.Substring(0, (5) - (0)).ToUpper().Equals("maps/".ToUpper())) { texture = texture.Substring(5); for (int i = 0; i < texture.Length; i++) { if (texture[i] == '/') { texture = texture.Substring(i + 1); break; } } } } catch (System.ArgumentOutOfRangeException e) { ; } // Find cubemap textures int numUnderscores = 0; bool validnumber = false; for (int i = texture.Length - 1; i > 0; i--) { if (texture[i] <= '9' && texture[i] >= '0') { // Current is a number, start building string validnumber = true; } else { if (texture[i] == '-') { // Current is a minus sign (-). if (!validnumber) { break; // Make sure there's a number to add the minus sign to. If not, kill the loop. } } else { if (texture[i] == '_') { // Current is an underscore (_) if (validnumber) { // Make sure there is a number in the current string numUnderscores++; // before moving on to the next one. validnumber = false; if (numUnderscores == 3) { // If we've got all our numbers texture = texture.Substring(0, (i) - (0)); // Cut the texture string break; // Kill the loop, we're done } } else { // No number after the underscore break; } } else { // Not an acceptable character break; } } } } } } } if (Double.IsInfinity(texScaleX) || Double.IsNaN(texScaleX)) { texScaleX = 1; } if (Double.IsInfinity(texScaleY) || Double.IsNaN(texScaleY)) { texScaleY = 1; } if (Double.IsInfinity(textureShiftS) || Double.IsNaN(textureShiftS)) { textureShiftS = 0; } if (Double.IsInfinity(textureShiftT) || Double.IsNaN(textureShiftT)) { textureShiftT = 0; } if (Double.IsInfinity(textureS.X) || Double.IsNaN(textureS.X) || Double.IsInfinity(textureS.Y) || Double.IsNaN(textureS.Y) || Double.IsInfinity(textureS.Z) || Double.IsNaN(textureS.Z)) { textureS = TexInfo.textureAxisFromPlane(inputData.Plane)[0]; } if (Double.IsInfinity(textureT.X) || Double.IsNaN(textureT.X) || Double.IsInfinity(textureT.Y) || Double.IsNaN(textureT.Y) || Double.IsInfinity(textureT.Z) || Double.IsNaN(textureT.Z)) { textureT = TexInfo.textureAxisFromPlane(inputData.Plane)[1]; } if (Settings.roundNums) { temp = "( " + MAPMaker.Round(triangle[0].X, 6) + " " + MAPMaker.Round(triangle[0].Y, 6) + " " + MAPMaker.Round(triangle[0].Z, 6) + " ) " + "( " + MAPMaker.Round(triangle[1].X, 6) + " " + MAPMaker.Round(triangle[1].Y, 6) + " " + MAPMaker.Round(triangle[1].Z, 6) + " ) " + "( " + MAPMaker.Round(triangle[2].X, 6) + " " + MAPMaker.Round(triangle[2].Y, 6) + " " + MAPMaker.Round(triangle[2].Z, 6) + " ) " + texture + " " + System.Math.Floor(textureShiftS) + " " + System.Math.Floor(textureShiftT) + " " + MAPMaker.FormattedRound(texRot, 2, "######0.00") + " " + MAPMaker.Round(texScaleX, 6) + " " + MAPMaker.Round(texScaleY, 6) + " " + flags + " 0 0 "; } else { temp = "( " + triangle[0].X + " " + triangle[0].Y + " " + triangle[0].Z + " ) " + "( " + triangle[1].X + " " + triangle[1].Y + " " + triangle[1].Z + " ) " + "( " + triangle[2].X + " " + triangle[2].Y + " " + triangle[2].Z + " ) " + texture + " " + textureShiftS + " " + textureShiftT + " " + texRot + " " + texScaleX + " " + texScaleY + " " + flags + " 0 0 "; } if (isDetail) { temp += "+surfaceparm detail "; } return(temp); } catch (System.NullReferenceException e) { DecompilerThread.OnMessage(this, "WARNING: Side with bad data! Not exported!"); return(""); } }
public MTOB(EndianBinaryReader er) { Type = er.ReadUInt32(); Signature = er.ReadString(Encoding.ASCII, 4); if (Signature != "MTOB") throw new SignatureNotCorrectException(Signature, "MTOB", er.BaseStream.Position); Revision = er.ReadUInt32(); NameOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); Unknown2 = er.ReadUInt32(); Unknown3 = er.ReadUInt32(); Flags = (MaterialFlags)er.ReadUInt32(); TexCoordConfig = er.ReadUInt32(); TranslucencyKind = er.ReadUInt32(); MaterialColor = new MaterialColorCtr(er); Rasterization = new RasterizationCtr(er); FragmentOperation = new FragmentOperationCtr(er); NrActiveTextureCoordiators = er.ReadUInt32(); TextureCoordiators = new TextureCoordinatorCtr[3]; TextureCoordiators[0] = new TextureCoordinatorCtr(er); TextureCoordiators[1] = new TextureCoordinatorCtr(er); TextureCoordiators[2] = new TextureCoordinatorCtr(er); TexMapper0Offset = er.ReadUInt32(); if (TexMapper0Offset != 0) TexMapper0Offset += (UInt32)er.BaseStream.Position - 4; TexMapper1Offset = er.ReadUInt32(); if (TexMapper1Offset != 0) TexMapper1Offset += (UInt32)er.BaseStream.Position - 4; TexMapper2Offset = er.ReadUInt32(); if (TexMapper2Offset != 0) TexMapper2Offset += (UInt32)er.BaseStream.Position - 4; ProcTexMapperOffset = er.ReadUInt32(); if (ProcTexMapperOffset != 0) ProcTexMapperOffset += (UInt32)er.BaseStream.Position - 4; ShaderOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); FragmentShaderOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); ShaderProgramDescriptionIndex = er.ReadUInt32(); NrShaderParameters = er.ReadUInt32(); ShaderParametersOffsetArrayOffset = er.ReadUInt32(); LightSetIndex = er.ReadUInt32(); FogIndex = er.ReadUInt32(); ShadingParameterHash = er.ReadUInt32(); ShaderParametersHash = er.ReadUInt32(); TextureCoordinatorsHash = er.ReadUInt32(); TextureSamplersHash = er.ReadUInt32(); TextureMappersHash = er.ReadUInt32(); MaterialColorHash = er.ReadUInt32(); RasterizationHash = er.ReadUInt32(); FragmentLightingHash = er.ReadUInt32(); FragmentLightingTableHash = er.ReadUInt32(); FragmentLightingTableParametersHash = er.ReadUInt32(); TextureCombinersHash = er.ReadUInt32(); AlphaTestHash = er.ReadUInt32(); FragmentOperationHash = er.ReadUInt32(); MaterialId = er.ReadUInt32(); long curpos = er.BaseStream.Position; er.BaseStream.Position = NameOffset; Name = er.ReadStringNT(Encoding.ASCII); if (TexMapper0Offset != 0) { er.BaseStream.Position = TexMapper0Offset; Tex0 = new TexInfo(er); } if (TexMapper1Offset != 0) { er.BaseStream.Position = TexMapper1Offset; Tex1 = new TexInfo(er); } if (TexMapper2Offset != 0) { er.BaseStream.Position = TexMapper2Offset; Tex2 = new TexInfo(er); } /*if (TexMapper3Offset != 0) { er.BaseStream.Position = Tex3Offset; Tex3 = new TexInfo(er); }*/ //TODO: Procedural Texture Mapper er.BaseStream.Position = ShaderOffset; Shader = new SHDR(er); er.BaseStream.Position = FragmentShaderOffset; FragShader = new FragmentShader(er); er.BaseStream.Position = curpos; }
protected override void OnUpdate(DX11RenderContext context) { bool resetta = true; try { var ptadesc = FOutTexArray[0][context].Description; resetta = FTADepth[0] != ptadesc.ArraySize || (int)FTASize[0].x != ptadesc.Width || (int)FTASize[0].y != ptadesc.Height || FTAFormat[0] != ptadesc.Format; } catch (Exception e) { } if (resetta) { try { FOutTexArray[0].Dispose(context); } catch (Exception e) { } var tadesc = new Texture2DDescription { ArraySize = FTADepth[0], Width = (int)FTASize[0].x, Height = (int)FTASize[0].y, Format = FTAFormat[0], BindFlags = BindFlags.UnorderedAccess | BindFlags.ShaderResource, //CpuAccessFlags = CpuAccessFlags.None, MipLevels = 1, OptionFlags = ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0), //Usage = ResourceUsage.Default }; FOutTexArray[0][context] = new DX11RWTextureArray2D(context, new Texture2D(context.Device, tadesc)); foreach (var semantic in CustomSemantics) { semantic.Dispose(); } CustomSemantics.Clear(); CustomSemantics.Add(new RWTexture2dArrayRenderSemantic("TEXTUREARRAY", false) { Data = FOutTexArray[0][context] }); CustomSemantics.Add(new Texture2dArrayRenderSemantic("TEXTUREARRAY_SRV", false) { Data = FOutTexArray[0][context] }); } TexInfo ti = this.rtm.GetRenderTarget(context); if (ti.w != this.width || ti.h != this.height || !this.targets.ContainsKey(context) || this.invalidate || ti.format != this.format) { this.invalidate = false; this.width = ti.w; this.height = ti.h; this.format = ti.format; this.depthmanager.NeedReset = true; if (targets.ContainsKey(context)) { context.ResourcePool.Unlock(targets[context]); } if (targetresolve.ContainsKey(context)) { context.ResourcePool.Unlock(targetresolve[context]); } int aacount = Convert.ToInt32(this.FInAASamplesPerPixel[0].Name); int aaquality = 0; if (aacount > 1) { List <SampleDescription> sds = context.GetMultisampleFormatInfo(ti.format); int maxlevels = sds[sds.Count - 1].Count; if (aacount > maxlevels) { FHost.Log(TLogType.Warning, "Multisample count too high for this format, reverted to: " + maxlevels); aacount = maxlevels; } DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0], this.FInSharedTex[0]).Element; DX11RenderTarget2D temptargetresolve = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(1, 0), this.FInDoMipMaps[0], this.FInMipLevel[0], this.FInSharedTex[0]).Element; targets[context] = temptarget; targetresolve[context] = temptargetresolve; this.FOutBuffers[0][context] = temptargetresolve; this.FOutAABuffers[0][context] = temptarget; } else { //Bind both texture as same output DX11RenderTarget2D temptarget = context.ResourcePool.LockRenderTarget(this.width, this.height, ti.format, new SampleDescription(aacount, aaquality), this.FInDoMipMaps[0], this.FInMipLevel[0], this.FInSharedTex[0]).Element; targets[context] = temptarget; this.FOutBuffers[0][context] = temptarget; this.FOutAABuffers[0][context] = temptarget; } } }
private int CompareNewMsg(TexInfo a, TexInfo b) { return(a.path.CompareTo(b.path)); }
public void Write(EndianBinaryWriter er) { long offpos = er.BaseStream.Position; //header.Write(er, 0); er.Write(Signature, Encoding.ASCII, false); er.Write((uint)0); List <byte> TexData = new List <byte>(); List <byte> Tex4x4Data = new List <byte>(); List <byte> Tex4x4PlttIdxData = new List <byte>(); foreach (DictTexData d in dictTex.entry.data) { if (d.Fmt != Textures.ImageFormat.COMP4x4) { TexData.AddRange(d.Data); } else { Tex4x4Data.AddRange(d.Data); Tex4x4PlttIdxData.AddRange(d.Data4x4); } } List <byte> PaletteData = new List <byte>(); foreach (DictPlttData d in dictPltt.entry.data) { PaletteData.AddRange(d.Data); } TexInfo.ofsDict = 60; TexInfo.sizeTex = (uint)TexData.Count; TexInfo.ofsTex = (UInt32)(60 + 8 + (dictTex.numEntry + 1) * 4 + 4 + dictTex.numEntry * 8 + dictTex.numEntry * 16 + 8 + (dictPltt.numEntry + 1) * 4 + 4 + dictPltt.numEntry * 4 + dictPltt.numEntry * 16); Tex4x4Info.ofsDict = 60; Tex4x4Info.sizeTex = (uint)Tex4x4Data.Count; Tex4x4Info.ofsTex = (UInt32)(60 + 8 + (dictTex.numEntry + 1) * 4 + 4 + dictTex.numEntry * 8 + dictTex.numEntry * 16 + 8 + (dictPltt.numEntry + 1) * 4 + 4 + dictPltt.numEntry * 4 + dictPltt.numEntry * 16 + TexData.Count); Tex4x4Info.ofsTexPlttIdx = (UInt32)(60 + 8 + (dictTex.numEntry + 1) * 4 + 4 + dictTex.numEntry * 8 + dictTex.numEntry * 16 + 8 + (dictPltt.numEntry + 1) * 4 + 4 + dictPltt.numEntry * 4 + dictPltt.numEntry * 16 + TexData.Count + Tex4x4Data.Count); PlttInfo.ofsDict = (ushort)(60 + 8 + (dictTex.numEntry + 1) * 4 + 4 + dictTex.numEntry * 8 + dictTex.numEntry * 16); PlttInfo.sizePltt = (uint)PaletteData.Count; PlttInfo.ofsPlttData = (UInt32)(60 + 8 + (dictTex.numEntry + 1) * 4 + 4 + dictTex.numEntry * 8 + dictTex.numEntry * 16 + 8 + (dictPltt.numEntry + 1) * 4 + 4 + dictPltt.numEntry * 4 + dictPltt.numEntry * 16 + TexData.Count + Tex4x4Data.Count + Tex4x4PlttIdxData.Count); TexInfo.Write(er); Tex4x4Info.Write(er); PlttInfo.Write(er); uint offset = 0; uint offset4x4 = 0; for (int i = 0; i < dictTex.numEntry; i++) { if (dictTex[i].Value.Fmt != Textures.ImageFormat.COMP4x4) { dictTex[i].Value.Offset = offset; offset += (uint)dictTex[i].Value.Data.Length; } else { dictTex[i].Value.Offset = offset4x4; offset4x4 += (uint)dictTex[i].Value.Data.Length; } } dictTex.Write(er); uint offsetPltt = 0; for (int i = 0; i < dictPltt.numEntry; i++) { dictPltt[i].Value.offset = offsetPltt; offsetPltt += (uint)dictPltt[i].Value.Data.Length; } dictPltt.Write(er); er.Write(TexData.ToArray(), 0, TexData.Count); er.Write(Tex4x4Data.ToArray(), 0, Tex4x4Data.Count); er.Write(Tex4x4PlttIdxData.ToArray(), 0, Tex4x4PlttIdxData.Count); er.Write(PaletteData.ToArray(), 0, PaletteData.Count); long curpos = er.BaseStream.Position; er.BaseStream.Position = offpos + 4; er.Write((UInt32)(curpos - offpos)); er.BaseStream.Position = curpos; }
private string brushSideToString(MAPBrushSide inputData) { try { string texture = inputData.Texture; if (BSPVersion == mapType.TYPE_SOURCE17 || BSPVersion == mapType.TYPE_SOURCE18 || BSPVersion == mapType.TYPE_SOURCE19 || BSPVersion == mapType.TYPE_SOURCE20 || BSPVersion == mapType.TYPE_SOURCE21 || BSPVersion == mapType.TYPE_SOURCE22 || BSPVersion == mapType.TYPE_SOURCE23 || BSPVersion == mapType.TYPE_DMOMAM || BSPVersion == mapType.TYPE_VINDICTUS || BSPVersion == mapType.TYPE_TACTICALINTERVENTION) { try { if (texture.Substring(0, (5) - (0)).ToUpper().Equals("maps/".ToUpper())) { texture = texture.Substring(5); for (int i = 0; i < texture.Length; i++) { if (texture[i] == '/') { texture = texture.Substring(i + 1); break; } } } } catch (System.ArgumentOutOfRangeException) { ; } // Find cubemap textures int numUnderscores = 0; bool validnumber = false; for (int i = texture.Length - 1; i > 0; i--) { if (texture[i] <= '9' && texture[i] >= '0') { // Current is a number, start building string validnumber = true; } else { if (texture[i] == '-') { // Current is a minus sign (-). if (!validnumber) { break; // Make sure there's a number to add the minus sign to. If not, kill the loop. } } else { if (texture[i] == '_') { // Current is an underscore (_) if (validnumber) { // Make sure there is a number in the current string numUnderscores++; // before moving on to the next one. validnumber = false; if (numUnderscores == 3) { // If we've got all our numbers texture = texture.Substring(0, (i) - (0)); // Cut the texture string break; // Kill the loop, we're done } } else { // No number after the underscore break; } } else { // Not an acceptable character break; } } } } } Plane plane = inputData.Plane; Vector3D textureS = inputData.TextureS; Vector3D textureT = inputData.TextureT; double textureShiftS = inputData.TextureShiftS; double textureShiftT = inputData.TextureShiftT; double texScaleX = inputData.TexScaleX; double texScaleY = inputData.TexScaleY; if (Double.IsInfinity(texScaleX) || Double.IsNaN(texScaleX)) { texScaleX = 1; } if (Double.IsInfinity(texScaleY) || Double.IsNaN(texScaleY)) { texScaleY = 1; } if (Double.IsInfinity(textureShiftS) || Double.IsNaN(textureShiftS)) { textureShiftS = 0; } if (Double.IsInfinity(textureShiftT) || Double.IsNaN(textureShiftT)) { textureShiftT = 0; } if (Double.IsInfinity(textureS.X) || Double.IsNaN(textureS.X) || Double.IsInfinity(textureS.Y) || Double.IsNaN(textureS.Y) || Double.IsInfinity(textureS.Z) || Double.IsNaN(textureS.Z)) { textureS = TexInfo.textureAxisFromPlane(inputData.Plane)[0]; } if (Double.IsInfinity(textureT.X) || Double.IsNaN(textureT.X) || Double.IsInfinity(textureT.Y) || Double.IsNaN(textureT.Y) || Double.IsInfinity(textureT.Z) || Double.IsNaN(textureT.Z)) { textureT = TexInfo.textureAxisFromPlane(inputData.Plane)[1]; } if (Settings.roundNums) { return("( " + MAPMaker.Round(plane.A, 10) + " " + MAPMaker.Round(plane.B, 10) + " " + MAPMaker.Round(plane.C, 10) + " " + MAPMaker.Round(plane.Dist, 10) + " ) " + "( ( 1 0 " + MAPMaker.Round(textureShiftS, 10) + " ) ( 0 1 " + MAPMaker.Round(textureShiftT, 10) + " ) ) " + "\"" + texture + "\" 0 0 0"); } else { return("( " + plane.A + " " + plane.B + " " + plane.C + " " + plane.Dist + " ) " + "( ( 1 0 " + textureShiftS + " ) ( 0 1 " + textureShiftT + " ) ) " + "\"" + texture + "\" 0 0 0"); } } catch (System.NullReferenceException e) { DecompilerThread.OnMessage(this, "WARNING: Side with bad data! Not exported!"); return(null); } }
// -decompileBrush38(Brush, int, boolean) // Decompiles the Brush and adds it to entitiy #currentEntity as .MAP data. private void decompileBrush(Brush brush, int currentEntity) { Vector3D origin = mapFile[currentEntity].Origin; int firstSide = brush.FirstSide; int numSides = brush.NumSides; MAPBrushSide[] brushSides = new MAPBrushSide[numSides]; bool isDetail = false; if (currentEntity == 0 && !Settings.noDetail && (brush.Contents[3] & ((sbyte)1 << 3)) != 0) { isDetail = true; } MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail); if (currentEntity == 0 && !Settings.noWater && (brush.Contents[0] & ((sbyte)1 << 5)) != 0) { mapBrush.Water = true; } //DecompilerThread.OnMessage(this, ": " + numSides + " sides, detail: " + isDetail); for (int i = 0; i < numSides; i++) { // For each side of the brush BrushSide currentSide = BSPObject.BrushSides[firstSide + i]; if (currentSide.isBevel() == 0) { // Bevel sides are evil Vector3D[] plane = new Vector3D[3]; // Three points define a plane. All I have to do is find three points on that plane. Plane currentPlane = BSPObject.Planes[currentSide.Plane]; // To find those three points, I must extrapolate from planes until I find a way to associate faces with brushes bool isDuplicate = false; /* TODO: We sure don't want duplicate planes (though this is already handled by the MAPBrush class). Make sure neither checked side is bevel. * for(int j=i+1;j<numSides;j++) { // For each subsequent side of the brush * if(currentPlane.equals(BSPObject.Planes.getPlane(BSPObject.getBrushSides()[firstSide+j).getPlane()))) { * DecompilerThread.OnMessage(this, "WARNING: Duplicate planes in a brush, sides "+i+" and "+j,Settings.VERBOSITY_WARNINGS); * isDuplicate=true; * } * }*/ if (!isDuplicate) { TexInfo currentTexInfo = null; string texture = "tools/toolsclip"; if (currentSide.Texture > -1) { currentTexInfo = BSPObject.TexInfo[currentSide.Texture]; } else { int dataIndex = BSPObject.findTexDataWithTexture("tools/toolsclip"); if (dataIndex >= 0) { currentTexInfo = new TexInfo(new Vector3D(0, 0, 0), 0, new Vector3D(0, 0, 0), 0, 0, dataIndex); } } if (currentTexInfo != null) { SourceTexData currentTexData; if (currentTexInfo.Texture >= 0) { // I've only found one case where this is a problem: c2a3a in HL Source. Don't know why. currentTexData = BSPObject.TexDatas[currentTexInfo.Texture]; texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]); } else { texture = "tools/toolsskip"; } } double[] textureU = new double[3]; double[] textureV = new double[3]; double textureShiftU = 0; double textureShiftV = 0; double texScaleU = 1; double texScaleV = 1; // Get the lengths of the axis vectors if ((texture.Length > 6 && texture.Substring(0, (6) - (0)).ToUpper().Equals("tools/".ToUpper())) || currentTexInfo == null) { // Tools textured faces do not maintain their own texture axes. Therefore, an arbitrary axis is // used in the compiled map. When decompiled, these axes might smear the texture on the face. Fix that. Vector3D[] axes = TexInfo.textureAxisFromPlane(currentPlane); textureU = axes[0].Point; textureV = axes[1].Point; } else { double SAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.SAxis.X, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.TAxis.X, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. texScaleV = (1 / TAxisLength); textureU[0] = ((double)currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double)currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double)currentTexInfo.SAxis.Z / SAxisLength); double originShiftU = (((double)currentTexInfo.SAxis.X / SAxisLength) * origin[X] + ((double)currentTexInfo.SAxis.Y / SAxisLength) * origin[Y] + ((double)currentTexInfo.SAxis.Z / SAxisLength) * origin[Z]) / texScaleU; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" textureShiftU = (double)currentTexInfo.SShift - originShiftU; textureV[0] = ((double)currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double)currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double)currentTexInfo.TAxis.Z / TAxisLength); double originShiftV = (((double)currentTexInfo.TAxis.X / TAxisLength) * origin[X] + ((double)currentTexInfo.TAxis.Y / TAxisLength) * origin[Y] + ((double)currentTexInfo.TAxis.Z / TAxisLength) * origin[Z]) / texScaleV; //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" textureShiftV = (double)currentTexInfo.TShift - originShiftV; } float texRot = 0; // In compiled maps this is calculated into the U and V axes, so set it to 0 until I can figure out a good way to determine a better value. int flags = 0; // Set this to 0 until we can somehow associate faces with brushes string material = "wld_lightmap"; // Since materials are a NightFire only thing, set this to a good default double lgtScale = 16; // These values are impossible to get from a compiled map since they double lgtRot = 0; // are used by RAD for generating lightmaps, then are discarded, I believe. brushSides[i] = new MAPBrushSide(currentPlane, texture, textureU, textureShiftU, textureV, textureShiftV, texRot, texScaleU, texScaleV, flags, material, lgtScale, lgtRot); mapBrush.add(brushSides[i]); } } } if (!Settings.skipPlaneFlip) { if (mapBrush.hasBadSide()) { // If there's a side that might be backward if (mapBrush.hasGoodSide()) { // If there's a side that is forward mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush); numSimpleCorrects++; if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { // If no forward side exists try { mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush); numAdvancedCorrects++; } catch (System.ArithmeticException) { DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { numGoodBrushes++; } } else { if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } // This adds the brush we've been finding and creating to // the current entity as an attribute. The way I've coded // this whole program and the entities parser, this shouldn't // cause any issues at all. if (Settings.brushesToWorld) { mapBrush.Water = false; mapFile[0].Brushes.Add(mapBrush); } else { mapFile[currentEntity].Brushes.Add(mapBrush); } }
private static void _Combine(CombineInfo combineInfo) { List <Mesh> meshList = new List <Mesh>(); try { CharacterAsset item = null; int i, j, k, count, count1, count2; List <CombineInstance> combineInstances = new List <CombineInstance>(); List <Transform> bones = new List <Transform>(); Transform[] transforms = combineInfo.root.GetComponentsInChildren <Transform>(); TexInfo[] texInfo = new TexInfo[combineInfo.items.Count]; SkinnedMeshRenderer smr = null; CombineInstance ci; string[] strs = null; string str = null; Transform transform; count2 = transforms.Length; count = (short)combineInfo.items.Count; for (i = 0; i < count; i++) { item = combineInfo.items[i]; smr = item.GetSkinnedMeshRenderer(); if (smr == null) { return; } Mesh mesh = Mesh.Instantiate(smr.sharedMesh) as Mesh; for (j = 0, count1 = smr.sharedMesh.subMeshCount; j < count1; j++) { ci = new CombineInstance(); ci.mesh = mesh; ci.subMeshIndex = j; combineInstances.Add(ci); } strs = item.GetBoneNames(); for (j = 0, count1 = strs.Length; j < count1; j++) { str = strs[j]; for (k = 0; k < count2; k++) { transform = transforms[k]; if (transform.name != str) { continue; } bones.Add(transform); break; } } meshList.Add(mesh); Object.Destroy(smr.gameObject); } TempLoad tl = null; string[] strArr = new string[count]; string destName; string path; int size; bool encrypt; Example.VersionFile.Type fileType; for (i = 0; i < count; i++) { item = combineInfo.items[i]; strs = item.GetTexNames(); tl = new TempLoad(); tl.texInfo = texInfo; tl.index = (short)i; tl.combineInstances = combineInstances; tl.bones = bones; tl.meshList = meshList; tl.endCombine = combineInfo.endCombine; tl.endParam = combineInfo.endParam; tl.root = combineInfo.root; tl.over = false; tl.plus = combineInfo.plus; tl.sub = combineInfo.sub; tl.autoTemp = combineInfo.autoTemp; tl.texName = strArr; tl.light = combineInfo.light; GameUtils.stringBuilder.Remove(0, GameUtils.stringBuilder.Length); GameUtils.stringBuilder.Append(strs[0]); ResUpdate.GetLoadDetails(GameUtils.stringBuilder.ToString(), out destName, out path, out size, out encrypt, out fileType); strArr[i] = GameUtils.stringBuilder.ToString(); ResLoader.LoadByPath(strArr[i], destName, path, fileType, size, OnLoad, tl, combineInfo.autoTemp); } } catch (System.Exception e) { for (int i = 0; i < meshList.Count; i++) { Object.Destroy(meshList[i]); } if (combineInfo != null && combineInfo.endCombine != null) { combineInfo.endCombine(null, -1, -1, combineInfo.endParam); } Debug.LogError("combine error->" + e.ToString()); } }
// METHODS // Attempt to turn the BSP into a .MAP file public virtual Entities decompile() { DecompilerThread.OnMessage(this, "Decompiling..."); // In the decompiler, it is not necessary to copy all entities to a new object, since // no writing is ever done back to the BSP file. mapFile = BSPObject.Entities; //int numAreaPortals=0; int numTotalItems = 0; int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count) / 100); if (onePercent < 1) { onePercent = 1; } int originalNumEntities = BSPObject.Entities.Count; // Need to keep track of this in this algorithm, since I create more entities on the fly for (int i = 0; i < originalNumEntities; i++) { // For each entity //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]); // getModelNumber() returns 0 for worldspawn, the *# for brush based entities, and -1 for everything else int currentModel = mapFile[i].ModelNumber; if (currentModel > -1) // If this is still -1 then it's strictly a point-based entity. Move on to the next one. { Leaf[] leaves = BSPObject.getLeavesInModel(currentModel); int numLeaves = leaves.Length; bool[] brushesUsed = new bool[BSPObject.Brushes.Count]; // Keep a list of brushes already in the model, since sometimes the leaves lump references one brush several times numBrshs = 0; // Reset the brush count for each entity for (int j = 0; j < numLeaves; j++) { // For each leaf in the bunch Leaf currentLeaf = leaves[j]; int firstMarkBrushIndex = currentLeaf.FirstMarkBrush; int numBrushIndices = currentLeaf.NumMarkBrushes; if (numBrushIndices > 0) { // A lot of leaves reference no brushes. If this is one, this iteration of the j loop is finished for (int k = 0; k < numBrushIndices; k++) { // For each brush referenced long currentBrushIndex = BSPObject.MarkBrushes[firstMarkBrushIndex + k]; if (!brushesUsed[(int)currentBrushIndex]) { // If the current brush has NOT been used in this entity //Console.Write("Brush " + numBrshs); brushesUsed[(int)currentBrushIndex] = true; Brush brush = BSPObject.Brushes[(int)currentBrushIndex]; decompileBrush(brush, i); // Decompile the brush numBrshs++; numTotalItems++; if (numTotalItems % onePercent == 0) { parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } } } } } numTotalItems++; // This entity if (numTotalItems % onePercent == 0) { parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.Count)); } } // Find displacement faces and generate brushes for them for (int i = 0; i < BSPObject.Faces.Count; i++) { Face face = BSPObject.Faces[i]; if (face.Displacement > -1) { SourceDispInfo disp = BSPObject.DispInfos[face.Displacement]; TexInfo currentTexInfo; if (face.Texture > -1) { currentTexInfo = BSPObject.TexInfo[face.Texture]; } else { Vector3D[] axes = TexInfo.textureAxisFromPlane(BSPObject.Planes[face.Plane]); currentTexInfo = new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip")); } SourceTexData currentTexData = BSPObject.TexDatas[currentTexInfo.Texture]; string texture = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]); double[] textureU = new double[3]; double[] textureV = new double[3]; // Get the lengths of the axis vectors double SAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.SAxis.X, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.TAxis.X, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. double texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. double texScaleV = (1 / TAxisLength); textureU[0] = ((double)currentTexInfo.SAxis.X / SAxisLength); textureU[1] = ((double)currentTexInfo.SAxis.Y / SAxisLength); textureU[2] = ((double)currentTexInfo.SAxis.Z / SAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftU = (double)currentTexInfo.SShift; textureV[0] = ((double)currentTexInfo.TAxis.X / TAxisLength); textureV[1] = ((double)currentTexInfo.TAxis.Y / TAxisLength); textureV[2] = ((double)currentTexInfo.TAxis.Z / TAxisLength); //UPGRADE_WARNING: Data types in Visual C# might be different. Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'" double textureShiftV = (double)currentTexInfo.TShift; if (face.NumEdges != 4) { DecompilerThread.OnMessage(this, "Displacement face with " + face.NumEdges + " edges!"); } // Turn vertices and edges into arrays of vectors Vector3D[] froms = new Vector3D[face.NumEdges]; Vector3D[] tos = new Vector3D[face.NumEdges]; for (int j = 0; j < face.NumEdges; j++) { if (BSPObject.SurfEdges[face.FirstEdge + j] > 0) { froms[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].FirstVertex].Vector; tos[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j]].SecondVertex].Vector; } else { tos[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j] * (-1)].FirstVertex].Vector; froms[j] = BSPObject.Vertices[BSPObject.Edges[(int)BSPObject.SurfEdges[face.FirstEdge + j] * (-1)].SecondVertex].Vector; } } MAPBrush displacementBrush = MAPBrush.createBrushFromWind(froms, tos, texture, "TOOLS/TOOLSNODRAW", currentTexInfo); MAPDisplacement mapdisp = new MAPDisplacement(disp, BSPObject.DispVerts.getVertsInDisp(disp.DispVertStart, disp.Power)); displacementBrush[0].Displacement = mapdisp; mapFile[0].Brushes.Add(displacementBrush); } } for (int i = 0; i < BSPObject.StaticProps.Count; i++) { Entity newStaticProp = new Entity("prop_static"); SourceStaticProp currentProp = BSPObject.StaticProps[i]; newStaticProp["model"] = BSPObject.StaticProps.Dictionary[currentProp.DictionaryEntry]; newStaticProp["skin"] = currentProp.Skin + ""; newStaticProp["origin"] = currentProp.Origin.X + " " + currentProp.Origin.Y + " " + currentProp.Origin.Z; newStaticProp["angles"] = currentProp.Angles.X + " " + currentProp.Angles.Y + " " + currentProp.Angles.Z; newStaticProp["solid"] = currentProp.Solidity + ""; newStaticProp["fademindist"] = currentProp.MinFadeDist + ""; newStaticProp["fademaxdist"] = currentProp.MaxFadeDist + ""; newStaticProp["fadescale"] = currentProp.ForcedFadeScale + ""; if (currentProp.Targetname != null) { newStaticProp["targetname"] = currentProp.Targetname; } mapFile.Add(newStaticProp); } for (int i = 0; i < BSPObject.Cubemaps.Count; i++) { Entity newCubemap = new Entity("env_cubemap"); SourceCubemap currentCube = BSPObject.Cubemaps[i]; newCubemap["origin"] = currentCube.Origin.X + " " + currentCube.Origin.Y + " " + currentCube.Origin.Z; newCubemap["cubemapsize"] = currentCube.Size + ""; mapFile.Add(newCubemap); } if (!Settings.skipPlaneFlip) { DecompilerThread.OnMessage(this, "Num simple corrected brushes: " + numSimpleCorrects); DecompilerThread.OnMessage(this, "Num advanced corrected brushes: " + numAdvancedCorrects); DecompilerThread.OnMessage(this, "Num good brushes: " + numGoodBrushes); } parent.OnProgress(this, 1.0); return(mapFile); }
// -decompileBrush(Brush, int) // Decompiles the Brush and adds it to entitiy #currentEntity as MAPBrush classes. private void decompileBrush(Brush brush, int currentEntity) { Vector3D origin = mapFile[currentEntity].Origin; int firstSide = brush.FirstSide; int numSides = brush.NumSides; if (firstSide < 0) { isCoD = true; firstSide = currentSideIndex; currentSideIndex += numSides; } MAPBrushSide[] brushSides = new MAPBrushSide[0]; bool isDetail = false; int brushTextureIndex = brush.Texture; byte[] contents = new byte[4]; if (brushTextureIndex >= 0) { contents = BSPObject.Textures[brushTextureIndex].Contents; } if (!Settings.noDetail && (contents[3] & ((byte)1 << 3)) != 0) { // This is the flag according to q3 source isDetail = true; // it's the same as Q2 (and Source), but I haven't found any Q3 maps that use it, so far } MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail); int numRealFaces = 0; Plane[] brushPlanes = new Plane[0]; //DecompilerThread.OnMessage(this, ": " + numSides + " sides"); if (!Settings.noWater && (contents[0] & ((byte)1 << 5)) != 0) { mapBrush.Water = true; } bool isVisBrush = false; for (int i = 0; i < numSides; i++) { // For each side of the brush BrushSide currentSide = BSPObject.BrushSides[firstSide + i]; int currentFaceIndex = currentSide.Face; Plane currentPlane; if (isCoD) { switch (i) { case 0: // XMin currentPlane = new Plane((double)(-1), (double)0, (double)0, (double)(-currentSide.Dist)); break; case 1: // XMax currentPlane = new Plane((double)1, (double)0, (double)0, (double)currentSide.Dist); break; case 2: // YMin currentPlane = new Plane((double)0, (double)(-1), (double)0, (double)(-currentSide.Dist)); break; case 3: // YMax currentPlane = new Plane((double)0, (double)1, (double)0, (double)currentSide.Dist); break; case 4: // ZMin currentPlane = new Plane((double)0, (double)0, (double)(-1), (double)(-currentSide.Dist)); break; case 5: // ZMax currentPlane = new Plane((double)0, (double)0, (double)1, (double)currentSide.Dist); break; default: currentPlane = BSPObject.Planes[currentSide.Plane]; break; } } else { currentPlane = BSPObject.Planes[currentSide.Plane]; } Vector3D[] triangle = new Vector3D[0]; // Three points define a plane. All I have to do is find three points on that plane. bool pointsWorked = false; int firstVertex = -1; int numVertices = 0; string texture = "noshader"; bool masked = false; if (currentFaceIndex > -1) { Face currentFace = BSPObject.Faces[currentFaceIndex]; int currentTextureIndex = currentFace.Texture; firstVertex = currentFace.FirstVertex; numVertices = currentFace.NumVertices; string mask = BSPObject.Textures[currentTextureIndex].Mask; if (mask.ToUpper().Equals("ignore".ToUpper()) || mask.Length == 0) { texture = BSPObject.Textures[currentTextureIndex].Name; } else { texture = mask.Substring(0, (mask.Length - 4) - (0)); // Because mask includes file extensions masked = true; } if (numVertices != 0 && !Settings.planarDecomp) { // If the face actually references a set of vertices triangle = new Vector3D[3]; double currentHighest = 0.0; // Find the combination of three vertices which gives the greatest area for (int p1 = 0; p1 < numVertices - 2; p1++) { for (int p2 = p1 + 1; p2 < numVertices - 1; p2++) { for (int p3 = p2 + 1; p3 < numVertices; p3++) { double currentArea = Vector3D.SqrTriangleArea(BSPObject.Vertices[firstVertex + p1].Vector, BSPObject.Vertices[firstVertex + p2].Vector, BSPObject.Vertices[firstVertex + p3].Vector); if (currentArea > Settings.precision * Settings.precision * 4.0) // Three collinear points will generate an area of 0 or almost 0 { pointsWorked = true; if (currentArea > currentHighest) { currentHighest = currentArea; triangle[0] = BSPObject.Vertices[firstVertex + p1].Vector; triangle[1] = BSPObject.Vertices[firstVertex + p2].Vector; triangle[2] = BSPObject.Vertices[firstVertex + p3].Vector; } } } } } } } else { // If face information is not available, use the brush side's info instead int currentTextureIndex = currentSide.Texture; if (currentTextureIndex >= 0) { string mask = BSPObject.Textures[currentTextureIndex].Mask; if (mask.ToUpper().Equals("ignore".ToUpper()) || mask.Length == 0) { texture = BSPObject.Textures[currentTextureIndex].Name; } else { texture = mask.Substring(0, (mask.Length - 4) - (0)); // Because mask includes file extensions masked = true; } } else { // If neither face or brush side has texture info, fall all the way back to brush. I don't know if this ever happens. if (brushTextureIndex >= 0) { // If none of them have any info, noshader string mask = BSPObject.Textures[brushTextureIndex].Mask; if (mask.ToUpper().Equals("ignore".ToUpper()) || mask.Length == 0) { texture = BSPObject.Textures[brushTextureIndex].Name; } else { texture = mask.Substring(0, (mask.Length - 4) - (0)); // Because mask includes file extensions masked = true; } } } } if (texture.ToUpper().Equals("textures/common/vis".ToUpper())) { isVisBrush = true; return; // TODO: Try to recreate the vis entity? It's impossible to recreate the links... } // Get the lengths of the axis vectors. // TODO: This information seems to be contained in Q3's vertex structure. But there doesn't seem // to be a way to directly link faces to brush sides. double UAxisLength = 1; double VAxisLength = 1; double texScaleS = 1; double texScaleT = 1; Vector3D[] textureAxes = TexInfo.textureAxisFromPlane(currentPlane); double originShiftS = (textureAxes[0].X * origin[X]) + (textureAxes[0].Y * origin[Y]) + (textureAxes[0].Z * origin[Z]); double originShiftT = (textureAxes[1].X * origin[X]) + (textureAxes[1].Y * origin[Y]) + (textureAxes[1].Z * origin[Z]); double textureShiftS; double textureShiftT; if (firstVertex >= 0) { textureShiftS = (double)BSPObject.Vertices[firstVertex].TexCoordX - originShiftS; textureShiftT = (double)BSPObject.Vertices[firstVertex].TexCoordY - originShiftT; } else { textureShiftS = 0 - originShiftS; textureShiftT = 0 - originShiftT; } float texRot = 0; string material; if (masked) { material = "wld_masked"; } else { material = "wld_lightmap"; } double lgtScale = 16; double lgtRot = 0; MAPBrushSide[] newList = new MAPBrushSide[brushSides.Length + 1]; for (int j = 0; j < brushSides.Length; j++) { newList[j] = brushSides[j]; } int flags; //if(Settings.noFaceFlags) { flags = 0; //} if (pointsWorked) { newList[brushSides.Length] = new MAPBrushSide(currentPlane, triangle, texture, textureAxes[0].Point, textureShiftS, textureAxes[1].Point, textureShiftT, texRot, texScaleS, texScaleT, flags, material, lgtScale, lgtRot); } else { newList[brushSides.Length] = new MAPBrushSide(currentPlane, texture, textureAxes[0].Point, textureShiftS, textureAxes[1].Point, textureShiftT, texRot, texScaleS, texScaleT, flags, material, lgtScale, lgtRot); } brushSides = newList; numRealFaces++; } for (int i = 0; i < brushSides.Length; i++) { mapBrush.add(brushSides[i]); } brushPlanes = new Plane[mapBrush.NumSides]; for (int i = 0; i < brushPlanes.Length; i++) { brushPlanes[i] = mapBrush[i].Plane; } if (isCoD && mapBrush.NumSides > 6) { // Now we need to get rid of all the sides that aren't used. Get a list of // the useless sides from one brush, and delete those sides from all of them, // since they all have the same sides. if (!Settings.dontCull && numSides > 6) { int[] badSides = MAPBrush.findUnusedPlanes(mapBrush); // Need to iterate backward, since these lists go from low indices to high, and // the index of all subsequent items changes when something before it is removed. if (mapBrush.NumSides - badSides.Length < 4) { DecompilerThread.OnMessage(this, "WARNING: Plane cull returned less than 4 sides for entity " + currentEntity + " brush " + numBrshs); } else { for (int i = badSides.Length - 1; i > -1; i--) { mapBrush.delete(badSides[i]); } } } } if (!Settings.skipPlaneFlip) { if (mapBrush.hasBadSide()) { // If there's a side that might be backward if (mapBrush.hasGoodSide()) { // If there's a side that is forward mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush); numSimpleCorrects++; if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { // If no forward side exists try { mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush); numAdvancedCorrects++; } catch (System.ArithmeticException) { DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { numGoodBrushes++; } } else { if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } // This adds the brush we've been finding and creating to // the current entity as an attribute. The way I've coded // this whole program and the entities parser, this shouldn't // cause any issues at all. if (Settings.brushesToWorld) { mapBrush.Water = false; worldspawn.Brushes.Add(mapBrush); } else { mapFile[currentEntity].Brushes.Add(mapBrush); } }
protected virtual void OnGUI() { GUILayout.BeginHorizontal(); resType = (EResType)EditorGUILayout.EnumPopup("资源目录", resType, GUILayout.MaxWidth(250)); m_Platform = (EPlatform)EditorGUILayout.EnumPopup("平台", m_Platform, GUILayout.MaxWidth(250)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); ETexType lastTexType = m_TexType; m_TexType = (ETexType)EditorGUILayout.EnumPopup("统计类型", m_TexType, GUILayout.MaxWidth(250)); if (lastTexType != m_TexType) { m_TexInfo = null; m_TexMat = null; m_Tex = null; m_PrefabSet = null; } EditorGUILayout.LabelField(string.Format("Total Count:{0} TotalSize:{1}KB-{2}MB ", m_TotalCount, m_TotalSize / 1024, m_TotalSize / 1024 / 1024)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); if (GUILayout.Button("Scan", GUILayout.MaxWidth(150))) { string resPath = resPaths[(int)resType]; FindTexs(resPath); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); typeScrollPos = GUILayout.BeginScrollView(typeScrollPos, false, false, GUILayout.MinHeight(400)); Dictionary <string, TexInfo> texMap = m_FormatMap; if (m_TexType == ETexType.Size) { texMap = m_SizeMap; } Dictionary <string, TexInfo> .Enumerator it = texMap.GetEnumerator(); while (it.MoveNext()) { GUILayout.BeginHorizontal(); string name = it.Current.Key; TexInfo ti = it.Current.Value; EditorGUILayout.LabelField(string.Format("{0} Count:{1} Size:{2}KB-{3}MB ", name, ti.texList.Count, ti.size / 1024, ti.size / 1024 / 1024), GUILayout.MaxWidth(400)); if (GUILayout.Button("Select", GUILayout.MaxWidth(50))) { m_TexInfo = ti; m_TexMat = null; m_Tex = null; m_PrefabSet = null; } GUILayout.EndHorizontal(); } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.BeginVertical(); texScrollPos = GUILayout.BeginScrollView(texScrollPos, false, false, GUILayout.MinHeight(400)); if (m_TexInfo != null) { for (int i = 0; i < m_TexInfo.texList.Count; ++i) { GUILayout.BeginHorizontal(); Texture tex = m_TexInfo.texList[i]; if (m_TexMat != null && m_Tex == tex) { EditorGUILayout.ObjectField(string.Format("{0} mat:{1}", tex.name, m_TexMat.Count), tex, typeof(Texture), true, GUILayout.MaxWidth(450)); } else { EditorGUILayout.ObjectField(tex.name, tex, typeof(Texture), true, GUILayout.MaxWidth(450)); } if (GUILayout.Button("Mat", GUILayout.MaxWidth(50))) { m_Tex = tex; m_TexMatMap.TryGetValue(m_Tex, out m_TexMat); m_PrefabSet = null; } GUILayout.EndHorizontal(); } } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); GUILayout.Space(10); GUILayout.BeginHorizontal(); GUILayout.BeginVertical(); matScrollPos = GUILayout.BeginScrollView(matScrollPos, false, false, GUILayout.MinHeight(400)); if (m_TexMat != null) { MatPrefabMat.Enumerator texMatIt = m_TexMat.GetEnumerator(); while (texMatIt.MoveNext()) { GUILayout.BeginHorizontal(); Material mat = texMatIt.Current.Key; EditorGUILayout.ObjectField(mat.name, mat, typeof(Material), true, GUILayout.MaxWidth(450)); GUILayout.EndHorizontal(); } } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.BeginVertical(); prefabScrollPos = GUILayout.BeginScrollView(prefabScrollPos, false, false, GUILayout.MinHeight(500)); if (m_PrefabSet != null) { PrefabSet.Enumerator prefabIt = m_PrefabSet.GetEnumerator(); while (prefabIt.MoveNext()) { GUILayout.BeginHorizontal(); GameObject prefab = prefabIt.Current; EditorGUILayout.ObjectField(prefab.name, prefab, typeof(GameObject), true, GUILayout.MaxWidth(550)); GUILayout.EndHorizontal(); } } EditorGUILayout.EndScrollView(); GUILayout.EndVertical(); GUILayout.EndHorizontal(); }
public virtual TexInfo createPerpTexInfo(Plane in_Renamed) { Vector3D[] axes = TexInfo.textureAxisFromPlane(in_Renamed); return(new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip"))); }
// METHODS public void readBSP() { try { byte[] theLump = new byte[0]; byte[] vis = new byte[0]; BSPObject = new BSP(BSPFile.FullName); Console.WriteLine("Opening " + BSPFile.FullName); for (int i = 0; i < 18; i++) { try { theLump = readLumpNum(i); switch (i) { case 0: BSPObject.Entities = Entity.createLump(theLump); break; case 1: BSPObject.Planes = Plane.createLump(theLump); break; case 2: BSPObject.Textures = Texture.createLump(theLump); break; case 3: BSPObject.Materials = Texture.createLump(theLump); break; case 4: BSPObject.Vertices = Vertex.createLump(theLump); break; case 5: BSPObject.Normals = new Lump <LumpObject>(theLump.Length, 0); break; case 6: BSPObject.Indices = new NumList(theLump, NumList.dataType.UINT); break; case 7: vis = theLump; break; case 8: BSPObject.Nodes = Node.createLump(theLump); break; case 9: BSPObject.Faces = Face.createLump(theLump); break; case 10: BSPObject.Lightmaps = new NumList(theLump, NumList.dataType.UBYTE); break; case 11: BSPObject.Leaves = Leaf.createLump(theLump); break; case 12: BSPObject.MarkSurfaces = new NumList(theLump, NumList.dataType.UINT); break; case 13: BSPObject.MarkBrushes = new NumList(theLump, NumList.dataType.UINT); break; case 14: BSPObject.Models = Model.createLump(theLump); break; case 15: BSPObject.Brushes = Brush.createLump(theLump); break; case 16: BSPObject.BrushSides = BrushSide.createLump(theLump); break; case 17: BSPObject.TexInfo = TexInfo.createLump(theLump); break; } } catch { dumpLump(theLump); } } try { int visLength = BSPObject.Leaves[2].PVS; if (visLength > 0 && vis.Length > 0) { BSPObject.Vis = new Lump <LumpObject>(vis, visLength); } } catch (ArgumentOutOfRangeException) {; } if (BSPObject.Vis == null) { BSPObject.Vis = new Lump <LumpObject>(0, 0); } BSPObject.printBSPReport(); } catch (System.IO.IOException) { Console.WriteLine("Unable to access BSP file! Is it open in another program?"); } br.Close(); }
private void InnerScanTex(Texture tex, string texPath) { AssetImporter assetImport = AssetImporter.GetAtPath(texPath); TextureImporter texImport = assetImport as TextureImporter; if (texImport == null) { XDebug.LogError(texPath); return; } int texSize = 0; TextureImporterFormat format; texImport.GetPlatformTextureSettings(m_Platform.ToString(), out texSize, out format); long sizePer32 = 1; switch (format) { case TextureImporterFormat.ETC_RGB4: sizePer32 = 1; break; case TextureImporterFormat.RGB24: sizePer32 = 6; break; case TextureImporterFormat.RGBA16: sizePer32 = 4; break; case TextureImporterFormat.RGBA32: sizePer32 = 8; break; case TextureImporterFormat.Alpha8: sizePer32 = 2; break; } long size = tex.width * tex.height * sizePer32 / 2; string sizeStr = string.Format("{0}x{0}", tex.width, tex.height); string formatStr = format.ToString(); TexInfo ti = null; if (!m_FormatMap.TryGetValue(formatStr, out ti)) { ti = new TexInfo(); m_FormatMap.Add(formatStr, ti); } ti.texList.Add(tex); ti.size += size; ti = null; if (!m_SizeMap.TryGetValue(sizeStr, out ti)) { ti = new TexInfo(); m_SizeMap.Add(sizeStr, ti); } ti.texList.Add(tex); ti.size += size; m_TotalSize += size; m_TotalCount++; }
// -decompileBrush38(Brush, int, boolean) // Decompiles the Brush and adds it to entitiy #currentEntity as .MAP data. private void decompileBrush(Brush brush, int currentEntity) { Vector3D origin = mapFile[currentEntity].Origin; int firstSide = brush.FirstSide; int numSides = brush.NumSides; bool isDetail = false; MAPBrushSide[] brushSides = new MAPBrushSide[numSides]; if (!Settings.noDetail && (brush.Contents[3] & ((sbyte)1 << 3)) != 0) { // According to Q2's source, this is the detail flag isDetail = true; } MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail); //DecompilerThread.OnMessage(this, ": " + numSides + " sides"); if (!Settings.noWater && (brush.Contents[0] & ((sbyte)1 << 5)) != 0) { mapBrush.Water = true; } for (int i = 0; i < numSides; i++) { // For each side of the brush Vector3D[] plane = new Vector3D[3]; // Three points define a plane. All I have to do is find three points on that plane. BrushSide currentSide = BSPObject.BrushSides[firstSide + i]; Plane currentPlane = BSPObject.Planes[currentSide.Plane]; // To find those three points, I must extrapolate from planes until I find a way to associate faces with brushes Texture currentTexture; bool isDuplicate = false; for (int j = i + 1; j < numSides; j++) { // For each subsequent side of the brush // For some reason, QUAKE 2 MAKES COPLANAR SIDES OF BRUSHES. I don't know why but it's stupid. if (currentPlane.Equals(BSPObject.Planes[BSPObject.BrushSides[firstSide + j].Plane])) { DecompilerThread.OnMessage(this, "WARNING: Duplicate planes in entity " + currentEntity + " brush " + numBrshs + ", sides " + i + " and " + j + " (BSP planes " + currentSide.Plane + " and " + BSPObject.BrushSides[firstSide + j].Plane); isDuplicate = true; } } if (!isDuplicate) { /* * if(!Settings.planarDecomp) { * // Find a face whose plane and texture information corresponds to the current side * // It doesn't really matter if it's the actual brush's face, just as long as it provides vertices. * SiNFace currentFace=null; * boolean faceFound=false; * for(int j=0;j<BSP.getSFaces().size();j++) { * currentFace=BSP.getSFaces().getFace(j); * if(currentFace.getPlane()==currentSide.getPlane() && currentFace.getTexInfo()==currentSide.getTexInfo() && currentFace.getNumEdges()>1) { * faceFound=true; * break; * } * } * if(faceFound) { * int markEdge=BSP.getMarkEdges().getInt(currentFace.getFirstEdge()); * int currentMarkEdge=0; * int firstVertex; * int secondVertex; * if(markEdge>0) { * firstVertex=BSP.getEdges().getEdge(markEdge).getFirstVertex(); * secondVertex=BSP.getEdges().getEdge(markEdge).getSecondVertex(); * } else { * firstVertex=BSP.getEdges().getEdge(-markEdge).getSecondVertex(); * secondVertex=BSP.getEdges().getEdge(-markEdge).getFirstVertex(); * } * int numVertices=currentFace.getNumEdges()+1; * boolean pointsWorked=false; * plane[0]=new Vector3D(BSP.getVertices().getVertex(firstVertex)); // Grab and store the first one * plane[1]=new Vector3D(BSP.getVertices().getVertex(secondVertex)); // The second should be unique from the first * boolean second=false; * if(plane[0].equals(plane[1])) { // If for some messed up reason they are the same * for(currentMarkEdge=1;currentMarkEdge<currentFace.getNumEdges();currentMarkEdge++) { // For each edge after the first one * markEdge=BSP.getMarkEdges().getInt(currentFace.getFirstEdge()+currentMarkEdge); * if(markEdge>0) { * plane[1]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(markEdge).getFirstVertex())); * } else { * plane[1]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(-markEdge).getSecondVertex())); * } * if(!plane[0].equals(plane[1])) { // Make sure the point isn't the same as the first one * second=false; * break; // If it isn't the same, this point is good * } else { * if(markEdge>0) { * plane[1]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(markEdge).getSecondVertex())); * } else { * plane[1]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(-markEdge).getFirstVertex())); * } * if(!plane[0].equals(plane[1])) { * second=true; * break; * } * } * } * } * if(second) { * currentMarkEdge++; * } * for(;currentMarkEdge<currentFace.getNumEdges();currentMarkEdge++) { * markEdge=BSP.getMarkEdges().getInt(currentFace.getFirstEdge()+currentMarkEdge); * if(second) { * if(markEdge>0) { * plane[2]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(markEdge).getFirstVertex())); * } else { * plane[2]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(-markEdge).getSecondVertex())); * } * if(!plane[2].equals(plane[0]) && !plane[2].equals(plane[1])) { // Make sure no point is equal to the third one * if((Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).X!=0) || // Make sure all * (Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).Y!=0) || // three points * (Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).Z!=0)) { // are not collinear * pointsWorked=true; * break; * } * } * } * // if we get to here, the first vertex of the edge failed, or was already used * if(markEdge>0) { // use the second vertex * plane[2]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(markEdge).getSecondVertex())); * } else { * plane[2]=new Vector3D(BSP.getVertices().getVertex(BSP.getEdges().getEdge(-markEdge).getFirstVertex())); * } * if(!plane[2].equals(plane[0]) && !plane[2].equals(plane[1])) { // Make sure no point is equal to the third one * if((Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).X!=0) || // Make sure all * (Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).Y!=0) || // three points * (Vector3D.crossProduct(plane[0].subtract(plane[1]), plane[0].subtract(plane[2])).Z!=0)) { // are not collinear * pointsWorked=true; * break; * } * } * // If we get here, neither point worked and we need to try the next edge. * second=true; * } * if(!pointsWorked) { * plane=Plane.generatePlanePoints(currentPlane); * } * } else { // Face not found * plane=Plane.generatePlanePoints(currentPlane); * } * } else { // Planar decomp only */ plane = Plane.generatePlanePoints(currentPlane); // } string texture = "special/clip"; double[] textureU = new double[3]; double[] textureV = new double[3]; double UShift = 0; double VShift = 0; double texScaleU = 1; double texScaleV = 1; if (currentSide.Texture > -1) { currentTexture = BSPObject.Textures[currentSide.Texture]; if ((currentTexture.Flags[0] & ((sbyte)1 << 2)) != 0) { texture = "special/sky"; } else { if ((currentTexture.Flags[1] & ((sbyte)1 << 1)) != 0) { texture = "special/skip"; } else { if ((currentTexture.Flags[1] & ((sbyte)1 << 0)) != 0) { if (currentEntity == 0) { texture = "special/hint"; // Hint was not used the same way in Quake 2 as other games. } else { // For example, a Hint brush CAN be used for a trigger in Q2 and is used as such a lot. texture = "special/trigger"; } } else { texture = currentTexture.Name; } } } // Get the lengths of the axis vectors double SAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexture.TexAxes.SAxis.X, 2) + System.Math.Pow((double)currentTexture.TexAxes.SAxis.Y, 2) + System.Math.Pow((double)currentTexture.TexAxes.SAxis.Z, 2)); double TAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexture.TexAxes.TAxis.X, 2) + System.Math.Pow((double)currentTexture.TexAxes.TAxis.Y, 2) + System.Math.Pow((double)currentTexture.TexAxes.TAxis.Z, 2)); // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length. texScaleU = (1 / SAxisLength); // Let's use these values using the lengths of the U and V axes we found above. texScaleV = (1 / TAxisLength); textureU[0] = ((double)currentTexture.TexAxes.SAxis.X / SAxisLength); textureU[1] = ((double)currentTexture.TexAxes.SAxis.Y / SAxisLength); textureU[2] = ((double)currentTexture.TexAxes.SAxis.Z / SAxisLength); textureV[0] = ((double)currentTexture.TexAxes.TAxis.X / TAxisLength); textureV[1] = ((double)currentTexture.TexAxes.TAxis.Y / TAxisLength); textureV[2] = ((double)currentTexture.TexAxes.TAxis.Z / TAxisLength); UShift = (double)currentTexture.TexAxes.SShift; VShift = (double)currentTexture.TexAxes.TShift; } else { Vector3D[] axes = TexInfo.textureAxisFromPlane(currentPlane); textureU = axes[0].Point; textureV = axes[1].Point; } double originShiftU = (textureU[0] * origin[X] + textureU[1] * origin[Y] + textureU[2] * origin[Z]) / texScaleU; double textureShiftU = UShift - originShiftU; double originShiftV = (textureV[0] * origin[X] + textureV[1] * origin[Y] + textureV[2] * origin[Z]) / texScaleV; double textureShiftV = VShift - originShiftV; float texRot = 0; // In compiled maps this is calculated into the U and V axes, so set it to 0 until I can figure out a good way to determine a better value. int flags = 0; // Set this to 0 until we can somehow associate faces with brushes string material = "wld_lightmap"; // Since materials are a NightFire only thing, set this to a good default double lgtScale = 16; // These values are impossible to get from a compiled map since they double lgtRot = 0; // are used by RAD for generating lightmaps, then are discarded, I believe. brushSides[i] = new MAPBrushSide(plane, texture, textureU, textureShiftU, textureV, textureShiftV, texRot, texScaleU, texScaleV, flags, material, lgtScale, lgtRot); mapBrush.add(brushSides[i]); } } if (!Settings.skipPlaneFlip) { if (mapBrush.hasBadSide()) { // If there's a side that might be backward if (mapBrush.hasGoodSide()) { // If there's a side that is forward mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush); numSimpleCorrects++; if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { // If no forward side exists try { mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush); numAdvancedCorrects++; } catch (System.ArithmeticException) { DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } else { numGoodBrushes++; } } else { if (Settings.calcVerts) { // This is performed in advancedcorrect, so don't use it if that's happening try { mapBrush = MAPBrush.CalcBrushVertices(mapBrush); } catch (System.NullReferenceException) { DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + ""); } } } // This adds the brush we've been finding and creating to // the current entity as an attribute. The way I've coded // this whole program and the entities parser, this shouldn't // cause any issues at all. if (Settings.brushesToWorld) { mapBrush.Water = false; mapFile[0].Brushes.Add(mapBrush); } else { mapFile[currentEntity].Brushes.Add(mapBrush); } }