/// <summary> /// Postprocesser to convert the texture referenced by <paramref name="patch"/> into one used by GTKRadiant, if necessary. /// </summary> /// <param name="patch">The <see cref="MAPPatch"/> to have its texture parsed.</param> private void PostProcessQuake3Texture(MAPPatch patch) { if (patch.texture.Length >= 9 && patch.texture.Substring(0, 9).Equals("textures/", StringComparison.InvariantCultureIgnoreCase)) { patch.texture = patch.texture.Substring(9); } }
/// <summary> /// Process the data in a <see cref="MAPPatch"/> into the passed <see cref="StringBuilder"/>. /// </summary> /// <param name="patch">The <see cref="MAPPatch"/> to process.</param> /// <param name="sb">A <see cref="StringBuilder"/> object to append processed data from <paramref name="patch"/> to.</param> private void ParsePatch(MAPPatch patch, StringBuilder sb) { sb.Append(" {\r\n patchDef2\r\n {\r\n") .Append(patch.texture) .Append("\r\n( ") .Append((int)Math.Round(patch.dims.x)) .Append(" ") .Append((int)Math.Round(patch.dims.y)) .Append(" 0 0 0 )\r\n(\r\n"); for (int i = 0; i < patch.dims.x; ++i) { sb.Append("( "); for (int j = 0; j < patch.dims.y; ++j) { Vertex vertex = patch.points[((int)Math.Round(patch.dims.x) * j) + i]; sb.Append("( ") .Append(vertex.position.x.ToString("###0.#####", format)) .Append(" ") .Append(vertex.position.y.ToString("###0.#####", format)) .Append(" ") .Append(vertex.position.z.ToString("###0.#####", format)) .Append(" ") .Append(vertex.uv0.x.ToString("###0.#####", format)) .Append(" ") .Append(vertex.uv0.y.ToString("###0.#####", format)) .Append(" ) "); } sb.Append(")\r\n"); } sb.Append(")\r\n }\r\n }\r\n"); }
/// <summary> /// Moves this <see cref="MAPPatch"/> object using the passed vector <paramref name="v"/>. /// </summary> /// <param name="mapBrushSide">This <see cref="MAPPatch"/>.</param> /// <param name="v">Translation vector.</param> public static void Translate(this MAPPatch mapPatch, Vector3 v) { for (int i = 0; i < mapPatch.points.Length; ++i) { VertexExtensions.Translate(mapPatch.points[i], v); } }
/// <summary> /// Moves this <see cref="MAPPatch"/> object using the passed vector <paramref name="v"/>. /// </summary> /// <param name="mapBrushSide">This <see cref="MAPPatch"/>.</param> /// <param name="v">Translation vector.</param> public static void Translate(this MAPPatch mapPatch, Vector3d v) { for (int i = 0; i < mapPatch.points.Length; ++i) { mapPatch.points[i].Translate(v); } }
public byte[] patchToByteArray(MAPPatch inData, int num) { string patch = "// Brush " + num + (char)0x0D + (char)0x0A + inData.ToString() + (char)0x0D + (char)0x0A; byte[] patchbytes = new byte[patch.Length]; for (int i = 0; i < patch.Length; i++) { patchbytes[i] = (byte)patch[i]; } return(patchbytes); }
/// <summary> /// Process the data in a <see cref="MAPPatch"/> into the passed <c>StringBuilder</c>. /// </summary> /// <param name="patch">The <see cref="MAPPatch"/> to process.</param> /// <param name="sb">A <c>StringBuilder</c> object to append processed data from <paramref name="patch"/> to.</param> private void ParsePatch(MAPPatch patch, StringBuilder sb) { sb.Append(" {\r\n patchDef5\r\n {\r\n ") .Append(patch.texture) .Append("\r\n ( ") .Append((int)Math.Round(patch.dims.X)) .Append(" ") .Append((int)Math.Round(patch.dims.Y)) .Append(" 0 0 0 0 8 )\r\n(\r\n"); for (int i = 0; i < patch.dims.X; ++i) { sb.Append("( "); for (int j = 0; j < patch.dims.Y; ++j) { Vertex vertex = patch.points[((int)Math.Round(patch.dims.X) * j) + i]; sb.Append("( ") .Append(vertex.position.X.ToString("###0.#####", format)) .Append(" ") .Append(vertex.position.Y.ToString("###0.#####", format)) .Append(" ") .Append(vertex.position.Z.ToString("###0.#####", format)) .Append(" ") .Append(vertex.uv0.X.ToString("###0.#####", format)) .Append(" ") .Append(vertex.uv0.Y.ToString("###0.#####", format)) .Append(" ") .Append(vertex.color.R.ToString(format)) .Append(" ") .Append(vertex.color.G.ToString(format)) .Append(" ") .Append(vertex.color.B.ToString(format)) .Append(" ") .Append(vertex.color.A.ToString(format)) .Append(" 0 ) "); } sb.Append(")\r\n"); } sb.Append(")\r\n }\r\n }\r\n"); }
/// <summary> /// Processes an <see cref="Entity"/> into a state where it can be output into a file that map editors can read. /// </summary> /// <param name="entity">The <see cref="Entity"/> to process.</param> /// <remarks>This method does not return anything, since the <see cref="Entity"/> object is modified by reference.</remarks> private void ProcessEntity(Entity entity) { int modelNumber = entity.modelNumber; // If this Entity has no modelNumber, then this is a no-op. No processing is needed. // A modelnumber of 0 indicates the world entity. if (modelNumber >= 0) { Model model = _bsp.models[modelNumber]; if (_bsp.brushes != null) { List <Brush> brushes = _bsp.GetBrushesInModel(model); if (brushes != null) { foreach (Brush brush in brushes) { MAPBrush result = ProcessBrush(brush, entity.origin); result.isWater |= (entity.className == "func_water"); if (_master.settings.brushesToWorld) { _bsp.entities.GetWithAttribute("classname", "worldspawn").brushes.Add(result); } else { entity.brushes.Add(result); } ++_itemsProcessed; ReportProgress(); } } } if (model.numLeafPatches > 0 && _bsp.markSurfaces != null && _bsp.patches != null) { HashSet <Patch> patches = new HashSet <Patch>(); List <long> leafPatchesInModel = _bsp.GetReferencedObjects <long>(model, "markSurfaces"); foreach (long leafPatch in leafPatchesInModel) { if (leafPatch >= 0) { patches.Add(_bsp.patches[(int)leafPatch]); } } foreach (Patch patch in patches) { if (_bsp.version != MapType.CoD || patch.patchType == 0) { MAPPatch mappatch = ProcessPatch(patch); MAPBrush newBrush = new MAPBrush(); newBrush.patch = mappatch; entity.brushes.Add(newBrush); } } } if (_bsp.faces != null) { List <Face> surfaces = _bsp.GetFacesInModel(model); foreach (Face face in surfaces) { if (face.displacement >= 0) { if (modelNumber != 0) { _master.Print("WARNING: Displacement not part of world in " + _bsp.MapNameNoExtension); } MAPDisplacement displacement = ProcessDisplacement(_bsp.dispInfos[face.displacement]); MAPBrush newBrush = face.CreateBrush(_bsp, 32); newBrush.sides[0].displacement = displacement; // If we are not decompiling to VMF, vis will need to skip this brush. newBrush.isDetail = true; entity.brushes.Add(newBrush); } else if (face.flags == 2) { MAPPatch patch = ProcessPatch(face); MAPBrush newBrush = new MAPBrush(); newBrush.patch = patch; entity.brushes.Add(newBrush); } else if ((_bsp.version == MapType.STEF2 || _bsp.version == MapType.STEF2Demo) && face.flags == 5) { if (modelNumber != 0) { _master.Print("WARNING: Terrain not part of world in " + _bsp.MapNameNoExtension); } MAPTerrainEF2 terrain = ProcessEF2Terrain(face); MAPBrush newBrush = new MAPBrush(); newBrush.ef2Terrain = terrain; entity.brushes.Add(newBrush); } } } // If this is model 0 (worldspawn) there are other things that need to be taken into account. if (modelNumber == 0) { if (_bsp.lodTerrains != null) { foreach (LODTerrain lodTerrain in _bsp.lodTerrains) { MAPTerrainMoHAA terrain = ProcessTerrainMoHAA(lodTerrain); MAPBrush newBrush = new MAPBrush(); newBrush.mohTerrain = terrain; entity.brushes.Add(newBrush); } } } entity.Remove("model"); } }
public MAPBrush(MAPPatch patch) { this.patch = patch; }
// METHODS // +decompile() // Attempts to convert the BSP file back 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 numTotalItems = 0; worldspawn = mapFile[mapFile.findAllWithAttribute("classname", "worldspawn")[0]]; int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count) / 100); if (onePercent < 1) { onePercent = 1; } // I need to go through each entity and see if it's brush-based. // Worldspawn is brush-based as well as any entity with model *#. for (int i = 0; i < BSPObject.Entities.Count; i++) { // For each entity //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]); numBrshs = 0; // Reset the brush count for each entity // 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. int firstBrush = BSPObject.Models[currentModel].FirstBrush; int numBrushes = BSPObject.Models[currentModel].NumBrushes; numBrshs = 0; for (int j = 0; j < numBrushes; j++) { // For each brush //Console.Write("Brush " + j); decompileBrush(BSPObject.Brushes[j + firstBrush], i); // Decompile the brush numBrshs++; numTotalItems++; if (numTotalItems % onePercent == 0) { parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count)); } } } numTotalItems++; if (numTotalItems % onePercent == 0) { parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count)); } } 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); } foreach (Face face in BSPObject.Faces) { if (face.Facetype == Face.faceType.PATCH) { MAPPatch mapPatch = new MAPPatch(face.PatchSize[0], face.PatchSize[1], BSPObject.Textures[face.Texture].Name); for (int i = 0; i < face.NumVertices; i++) { mapPatch.Add(BSPObject.Vertices[face.FirstVertex + i]); } MAPBrush mapBrush = new MAPBrush(mapPatch); worldspawn.Brushes.Add(mapBrush); } } parent.OnProgress(this, 1.0); return(mapFile); }
public byte[] patchToByteArray(MAPPatch inData, int num) { string patch = "// Brush " + num + (char) 0x0D + (char) 0x0A + inData.ToString() + (char) 0x0D + (char) 0x0A; byte[] patchbytes = new byte[patch.Length]; for (int i = 0; i < patch.Length; i++) { patchbytes[i] = (byte) patch[i]; } return patchbytes; }
public MAPBrush(MAPPatch patch) { this.patch = patch; }
// METHODS // +decompile() // Attempts to convert the BSP file back 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 numTotalItems = 0; worldspawn = mapFile[mapFile.findAllWithAttribute("classname", "worldspawn")[0]]; int onePercent = (int)((BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count)/100); if(onePercent < 1) { onePercent = 1; } // I need to go through each entity and see if it's brush-based. // Worldspawn is brush-based as well as any entity with model *#. for (int i = 0; i < BSPObject.Entities.Count; i++) { // For each entity //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]); numBrshs = 0; // Reset the brush count for each entity // 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. int firstBrush = BSPObject.Models[currentModel].FirstBrush; int numBrushes = BSPObject.Models[currentModel].NumBrushes; numBrshs = 0; for (int j = 0; j < numBrushes; j++) { // For each brush //Console.Write("Brush " + j); decompileBrush(BSPObject.Brushes[j + firstBrush], i); // Decompile the brush numBrshs++; numTotalItems++; if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count)); } } } numTotalItems++; if(numTotalItems%onePercent == 0) { parent.OnProgress(this, numTotalItems/(double)(BSPObject.Brushes.Count + BSPObject.Entities.Count + BSPObject.Faces.Count)); } } 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); } foreach(Face face in BSPObject.Faces) { if(face.Facetype == Face.faceType.PATCH) { MAPPatch mapPatch = new MAPPatch(face.PatchSize[0], face.PatchSize[1], BSPObject.Textures[face.Texture].Name); for(int i=0; i<face.NumVertices; i++) { mapPatch.Add(BSPObject.Vertices[face.FirstVertex+i]); } MAPBrush mapBrush = new MAPBrush(mapPatch); worldspawn.Brushes.Add(mapBrush); } } parent.OnProgress(this, 1.0); return mapFile; }