private byte[] brushToByteArray(MAPBrush inData, int num)
    {
        if (inData.Patch != null)
        {
            return(patchToByteArray(inData.Patch, num));
        }
        if (inData.NumSides < 4)
        {
            // Can't create a brush with less than 4 sides
            DecompilerThread.OnMessage(this, "WARNING: Tried to create brush from " + inData.NumSides + " sides!");
            return(new byte[0]);
        }
        string brush = "// brush " + num + (char)0x0D + (char)0x0A + "{" + (char)0x0D + (char)0x0A;

        for (int i = 0; i < inData.NumSides; i++)
        {
            brush += (brushSideToString(inData[i], (inData.Detail || inData[0].Displacement != null)) + (char)0x0D + (char)0x0A);
        }
        brush += ("}" + (char)0x0D + (char)0x0A);
        if (brush.Length < 45)
        {
            // Any brush this short contains no sides.
            DecompilerThread.OnMessage(this, "WARNING: Brush with no sides being written! Oh no!");
            return(new byte[0]);
        }
        else
        {
            byte[] brushbytes = new byte[brush.Length];
            for (int i = 0; i < brush.Length; i++)
            {
                brushbytes[i] = (byte)brush[i];
            }
            return(brushbytes);
        }
    }
Ejemplo n.º 2
0
	// CONSTRUCTORS
	
	// This constructor sets everything according to specified settings.
	public BSP42Decompiler(BSP BSPObject, int jobnum, DecompilerThread parent)
	{
		// Set up global variables
		this.BSPObject = BSPObject;
		this.jobnum = jobnum;
		this.parent = parent;
	}
Ejemplo n.º 3
0
    // CONSTRUCTORS

    // This constructor sets everything according to specified settings.
    public BSP42Decompiler(BSP BSPObject, int jobnum, DecompilerThread parent)
    {
        // Set up global variables
        this.BSPObject = BSPObject;
        this.jobnum    = jobnum;
        this.parent    = parent;
    }
Ejemplo n.º 4
0
    private byte[] brushToByteArray(MAPBrush inBrush, int num)
    {
        if (inBrush.NumSides < 4)
        {
            // Can't create a brush with less than 4 sides
            DecompilerThread.OnMessage(this, "WARNING: Tried to create brush from " + inBrush.NumSides + " sides!");
            return(new byte[0]);
        }
        string brush = "// primitive " + num + (char)0x0A + "{" + (char)0x0A + " brushDef3" + (char)0x0A + " {" + (char)0x0A;

        for (int i = 0; i < inBrush.NumSides; i++)
        {
            brush += ("  " + brushSideToString(inBrush[i]) + (char)0x0A);
        }
        brush += (" }" + (char)0x0A + "}" + (char)0x0A);
        if (brush.Length < 58)
        {
            // Any brush this short contains no sides.
            DecompilerThread.OnMessage(this, "WARNING: Brush with no sides being written! Oh no!");
            return(new byte[0]);
        }
        else
        {
            byte[] brushbytes = new byte[brush.Length];
            for (int i = 0; i < brush.Length; i++)
            {
                brushbytes[i] = (byte)brush[i];
            }
            return(brushbytes);
        }
    }
 public Job(int id, string map, DecompilerThread runnable)
 {
     this.id                  = id;
     this.map                 = map;
     this.runnable            = runnable;
     runnable.reportProgress += new ProgressEventHandler(updateProgress);
 }
Ejemplo n.º 6
0
    // +getLeavesInModel(int)
    // Returns an array of Leaf containing all the leaves referenced from
    // this model's head node. This array cannot be referenced by index numbers
    // from other lumps, but if simply iterating through, getting information
    // it'll be just fine.
    public virtual Leaf[] getLeavesInModel(int model)
    {
        int head = models[model].HeadNode;

        if (head < 0)
        {
            //head = Math.Abs(head);
            DecompilerThread.OnMessage(this, "WARNING: Model " + model + " links to a negative node!");
        }
        return(getLeavesInNode(head));
    }
Ejemplo n.º 7
0
    // METHODS

    // renameAttribute(String, String)
    // Renames the specified attribute to the second String.
    public virtual void renameAttribute(string attribute, string to)
    {
        if (attributes.ContainsKey(attribute))
        {
            string val = attributes[attribute];
            attributes.Remove(attribute);
            if (attributes.ContainsKey(to))
            {
                attributes.Remove(to); DecompilerThread.OnMessage(this, "WARNING: Attribute " + to + " already existed in entity, overwritten!");
            }
            attributes.Add(to, val);
        }
    }
 private void SetOriginSize_Click(object sender, RoutedEventArgs e)
 {
     try {
         double input = Double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Please enter a new origin brush size.\nCurrent value: " + Settings.originBrushSize, "Enter new origin brush size", Settings.originBrushSize.ToString(), -1, -1));
         if (input <= 0)
         {
             throw new Exception("f**k");
         }
         Settings.precision = input;
     } catch {
         DecompilerThread.OnMessage(this, "Invalid origin brush size! Please enter a positive number.");
     }
 }
 private void NumThreads_Click(object sender, RoutedEventArgs e)
 {
     try {
         int input = Int32.Parse(Microsoft.VisualBasic.Interaction.InputBox("Please enter number of concurrent decompiles allowed.\nCurrent value: " + Settings.numThreads, "Enter new thread amount", Settings.numThreads.ToString(), -1, -1));
         if (input < 1)
         {
             throw new Exception("f**k");
         }
         Settings.numThreads = input;
     } catch {
         DecompilerThread.OnMessage(this, "Please enter a whole number greater than 0!");
     }
 }
Ejemplo n.º 10
0
 private void Ppts_Click(object sender, RoutedEventArgs e)
 {
     try {
         double input = Double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Please enter plane point coefficient.\nCurrent Value: " + Settings.planePointCoef, "Enter new coefficient", Settings.planePointCoef.ToString(), -1, -1));
         if (input == 0)
         {
             throw new Exception("f**k");
         }
         Settings.planePointCoef = input;
     } catch {
         DecompilerThread.OnMessage(this, "Invalid plane point coefficient! Please enter a nonzero number!");
     }
 }
Ejemplo n.º 11
0
 private void SetEpsilon_Click(object sender, RoutedEventArgs e)
 {
     try {
         double input = Double.Parse(Microsoft.VisualBasic.Interaction.InputBox("Please enter a new error tolerance value.\n" +
                                                                                "This value is used to compensate for error propagation in double precision calculations.\n" +
                                                                                "Typical values are between 0.0001 and 0.5. Current value: " + Settings.precision, "Enter new error tolerance", Settings.precision.ToString(), -1, -1));
         if (input < 0)
         {
             throw new Exception("f**k");
         }
         Settings.precision = input;
     } catch {
         DecompilerThread.OnMessage(this, "Invalid error tolerance! Please enter a positive number or 0.");
     }
 }
Ejemplo n.º 12
0
    // METHODS

    // toString()
    // Returns the brush side exactly as it would look in a .MAP file.
    // This is on multiple lines simply for readability. the returned
    // String will have no line breaks. This isn't used anymore for
    // file output, this would be slower.
    public override string ToString()
    {
        try {
            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) {
            DecompilerThread.OnMessage(this, "WARNING: Side with bad data! Not exported!");
            return(null);
        }
    }
Ejemplo n.º 13
0
 private void SetMMSS_Click(object sender, RoutedEventArgs e)
 {
     try {
         int input = Int32.Parse(Microsoft.VisualBasic.Interaction.InputBox("Please enter a new multimanager stack size.\n" +
                                                                            "When converting other entity systems to Source Engine entity I/O, you must recurse through\n" +
                                                                            "multi_managers. If they reference each other in a cycle, it will loop forever. The stack prevents\n" +
                                                                            "this from happening. Increase this to recurse further. Current value: " + Settings.mmStack, "Enter new stack size", Settings.mmStack.ToString(), -1, -1));
         if (input < 0)
         {
             throw new Exception("f**k");
         }
         Settings.mmStack = input;
     } catch {
         DecompilerThread.OnMessage(this, "Invalid stack size! Please enter a whole positive number or 0.");
     }
 }
Ejemplo n.º 14
0
 // METHODS
 private void StartNextIfAble()
 {
     if (jobQueue.Count > 0)
     {
         if (active.Count < Settings.numThreads)
         {
             DecompilerThread next = jobQueue.Dequeue();
             active.Add(next, new Thread(next.Run));
             active[next].Start();
             StartNextIfAble();                     // Recursively call this until either the queue is empty or the active jobs is full
         }
     }
     else
     {
         System.GC.Collect();                 // No jobs currently processing; use as little memory as possible ;)
     }
 }
Ejemplo n.º 15
0
 private void SaveLog_Click(object sender, RoutedEventArgs e)
 {
     try {
         SaveFileDialog dialog = new SaveFileDialog();
         dialog.Filter = "Text file|*.txt";
         if (dialog.ShowDialog() == true)
         {
             FileStream   stream = new FileStream(dialog.FileName, FileMode.Create, FileAccess.Write);
             BinaryWriter bw     = new BinaryWriter(stream);
             stream.Seek(0, SeekOrigin.Begin);
             bw.Write(txtConsole.Text);
             bw.Close();
         }
     } catch {
         DecompilerThread.OnMessage(this, "Unable to write file! Make sure the file is not read-only and that you have access to it.");
     }
 }
Ejemplo n.º 16
0
 private void OutFolder_Click(object sender, RoutedEventArgs e)
 {
     try {
         System.Windows.Forms.FolderBrowserDialog dialog = new System.Windows.Forms.FolderBrowserDialog();
         if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
         {
             Settings.outputFolder = dialog.SelectedPath + "\\";
             DecompilerThread.OnMessage(this, Settings.outputFolder);
         }
         else
         {
             Settings.outputFolder = "default";
         }
     } catch {
         Settings.outputFolder = "default";
     }
 }
Ejemplo n.º 17
0
		private void FileOpen_Click(Object sender, RoutedEventArgs e) {
			OpenFileDialog fileOpener = new OpenFileDialog();
			fileOpener.Filter = "All Supported Files|*.bsp;*.d3dbsp;*.wad|BSP Files|*.bsp;*.d3dbsp|WAD Files|*.wad|All Files|*.*";
			fileOpener.Multiselect = true;

			// Process open file dialog box results 
			if (fileOpener.ShowDialog() == true) {
				string[] filesToOpen = fileOpener.FileNames;
				for(int i=0;i<filesToOpen.Length;i++) {
					DecompilerThread thread = new DecompilerThread(new FileInfo(filesToOpen[i]), finished + active.Count + jobQueue.Count, Settings.openAs);
					Job theJob = new Job(finished + active.Count + jobQueue.Count, filesToOpen[i], thread);
					theJob.PropertyChanged += new PropertyChangedEventHandler(UpdateTaskbar);
					thread.error += new ErrorHandler(Error);
					jobQueue.Enqueue(thread);
					jobs.Add(theJob);
				}
				StartNextIfAble();
			}
		}
Ejemplo n.º 18
0
 // If only one thread is allowed to use new Object() method at once, only one map will be saved at once, meaning less
 // jumping hard drive seek time used.
 public static void write(byte[] data, string destinationString, bool toVMF)
 {
     try
     {
         if (!destinationString.Substring(destinationString.Length - 4).ToUpper().Equals(".map".ToUpper()) && !destinationString.Substring(destinationString.Length - 4).ToUpper().Equals(".vmf".ToUpper()))
         {
             if (toVMF)
             {
                 destinationString = destinationString + ".vmf";
             }
             else
             {
                 destinationString = destinationString + ".map";
             }
         }
     }
     catch (System.ArgumentOutOfRangeException)
     {
         if (toVMF)
         {
             destinationString = destinationString + ".vmf";
         }
         else
         {
             destinationString = destinationString + ".map";
         }
     }
     DecompilerThread.OnMessage(new Object(), "Saving " + destinationString + "...");
     try {
         FileStream   stream = new FileStream(destinationString, FileMode.Create, FileAccess.Write);
         BinaryWriter bw     = new BinaryWriter(stream);
         stream.Seek(0, SeekOrigin.Begin);
         bw.Write(data);
         bw.Close();
     } catch (System.IO.IOException e) {
         DecompilerThread.OnMessage(new Object(), "ERROR: Could not save " + destinationString + ", ensure the file is not open in another program.");
         throw e;
     }
 }
Ejemplo n.º 19
0
        private void FileOpen_Click(Object sender, RoutedEventArgs e)
        {
            OpenFileDialog fileOpener = new OpenFileDialog();

            fileOpener.Filter      = "All Supported Files|*.bsp;*.d3dbsp;*.wad|BSP Files|*.bsp;*.d3dbsp|WAD Files|*.wad|All Files|*.*";
            fileOpener.Multiselect = true;

            // Process open file dialog box results
            if (fileOpener.ShowDialog() == true)
            {
                string[] filesToOpen = fileOpener.FileNames;
                for (int i = 0; i < filesToOpen.Length; i++)
                {
                    DecompilerThread thread = new DecompilerThread(new FileInfo(filesToOpen[i]), finished + active.Count + jobQueue.Count, Settings.openAs);
                    Job theJob = new Job(finished + active.Count + jobQueue.Count, filesToOpen[i], thread);
                    theJob.PropertyChanged += new PropertyChangedEventHandler(UpdateTaskbar);
                    thread.error           += new ErrorHandler(Error);
                    jobQueue.Enqueue(thread);
                    jobs.Add(theJob);
                }
                StartNextIfAble();
            }
        }
Ejemplo n.º 20
0
 public virtual void  setSide(Plane plane, Vector3D[] triangle)
 {
     if (triangle.Length >= 3)
     {
         if (triangle[0] == null)
         {
             DecompilerThread.OnMessage(this, "WARNING: Tried to set triangle but point 0 was null!");
         }
         else
         {
             if (triangle[1] == null)
             {
                 DecompilerThread.OnMessage(this, "WARNING: Tried to set triangle but point 1 was null!");
             }
             else
             {
                 if (triangle[2] == null)
                 {
                     DecompilerThread.OnMessage(this, "WARNING: Tried to set triangle but point 2 was null!");
                 }
                 else
                 {
                     this.triangle[0] = triangle[0];
                     this.triangle[1] = triangle[1];
                     this.triangle[2] = triangle[2];
                     triangleDefined  = true;
                     this.plane       = plane;
                     planeDefined     = true;
                 }
             }
         }
     }
     else
     {
         DecompilerThread.OnMessage(this, "WARNING: Tried to define side with " + triangle.Length + " points!");
     }
 }
Ejemplo n.º 21
0
    // METHODS

    // -decompile()
    // Attempts to convert the Nightfire BSP file back into a .MAP file.
    //
    // This is another one of the most complex things I've ever had to code. I've
    // never nested for loops four deep before.
    // Iterators:
    // i: Current entity in the list
    //  j: Current leaf, referenced in a list by the model referenced by the current entity
    //   k: Current brush, referenced in a list by the current leaf.
    //	l: Current side of the current brush.
    //	 m: When attempting vertex decompilation, the current vertex.
    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;
        int onePercent    = (int)((BSPObject.Brushes.Count + BSPObject.Entities.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"]);
            // 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    firstLeaf   = BSPObject.Models[currentModel].FirstLeaf;
                int    numLeaves   = BSPObject.Models[currentModel].NumLeaves;
                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;
                for (int j = 0; j < numLeaves; j++)
                {
                    // For each leaf in the bunch
                    Leaf currentLeaf     = BSPObject.Leaves[j + firstLeaf];
                    int  firstBrushIndex = 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
                            if (!brushesUsed[(int)BSPObject.MarkBrushes[firstBrushIndex + k]])
                            {
                                // If the current brush has NOT been used in this entity
                                //Console.Write("Brush " + numBrshs);
                                brushesUsed[(int)BSPObject.MarkBrushes[firstBrushIndex + k]] = true;
                                decompileBrush(BSPObject.Brushes[(int)BSPObject.MarkBrushes[firstBrushIndex + k]], i);                                  // Decompile the brush
                                numBrshs++;
                                numTotalItems++;
                                if (numTotalItems % onePercent == 0)
                                {
                                    parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.Count));
                                }
                            }
                        }
                    }
                }
            }
            numTotalItems++;
            if (numTotalItems % onePercent == 0)
            {
                parent.OnProgress(this, numTotalItems / (double)(BSPObject.Brushes.Count + BSPObject.Entities.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);
        }
        parent.OnProgress(this, 1.0);
        return(mapFile);
    }
Ejemplo n.º 22
0
    public virtual void Run()
    {
        DateTime begin = DateTime.Now;

        try {
            Entities output = null;
            if (doomMap != null)
            {
                // If this is a Doom map extracted from a WAD
                //Window.setProgress(jobnum, 0, doomMap.getSubSectors().size(), "Decompiling...");
                WADDecompiler decompiler = new WADDecompiler(doomMap, jobnum, this);
                output = decompiler.decompile();
            }
            else
            {
                DecompilerThread.OnMessage(this, "Opening file " + BSPFile.FullName);
                //Window.setProgress(jobnum, 0, 1, "Reading...");
                BSPReader reader = new BSPReader(BSPFile, openAs);
                reader.readBSP();
                //if (!reader.WAD) {
                BSPObject = reader.BSPData;

                /*try {
                 *      Window.setProgress(jobnum, 0, reader.BSPData.getBrushes().size() + reader.BSPData.getEntities().size(), "Decompiling...");
                 * } catch (System.NullReferenceException e) {
                 *      try {
                 *              Window.setProgress(jobnum, 0, reader.BSPData.getLeaves().size() + reader.BSPData.getEntities().size(), "Decompiling...");
                 *      } catch (System.NullReferenceException f) {
                 *              Window.setProgress(jobnum, 0, 1, "Decompiling..."); // What's going on here? Put in a failsafe progress bar for now
                 *      }
                 * }*/

                switch (reader.Version)
                {
                case mapType.TYPE_QUAKE:
                    //DecompilerThread.OnMessage(this, "ERROR: Algorithm for decompiling Quake BSPs not written yet.",Window.VERBOSITY_ALWAYS);
                    //throw new java.lang.Exception(); // Throw an exception to the exception handler to indicate it didn't work
                    QuakeDecompiler decompiler29 = new QuakeDecompiler(reader.BSPData, jobnum, this);
                    output = decompiler29.decompile();
                    break;

                case mapType.TYPE_NIGHTFIRE:
                    BSP42Decompiler decompiler42 = new BSP42Decompiler(reader.BSPData, jobnum, this);
                    output = decompiler42.decompile();
                    break;

                case mapType.TYPE_QUAKE2:
                case mapType.TYPE_SIN:
                case mapType.TYPE_SOF:
                case mapType.TYPE_DAIKATANA:
                    BSP38Decompiler decompiler38 = new BSP38Decompiler(reader.BSPData, jobnum, this);
                    output = decompiler38.decompile();
                    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_DMOMAM:
                case mapType.TYPE_VINDICTUS:
                case mapType.TYPE_TACTICALINTERVENTION:
                    SourceBSPDecompiler sourceDecompiler = new SourceBSPDecompiler(reader.BSPData, jobnum, this);
                    output = sourceDecompiler.decompile();
                    break;

                case mapType.TYPE_QUAKE3:
                case mapType.TYPE_RAVEN:
                case mapType.TYPE_COD:
                case mapType.TYPE_COD2:
                case mapType.TYPE_COD4:
                case mapType.TYPE_STEF2:
                case mapType.TYPE_STEF2DEMO:
                case mapType.TYPE_MOHAA:
                case mapType.TYPE_FAKK:
                    BSP46Decompiler decompiler46 = new BSP46Decompiler(reader.BSPData, jobnum, this);
                    output = decompiler46.decompile();
                    break;

                case mapType.TYPE_DOOM:
                case mapType.TYPE_HEXEN:
                    foreach (DoomMap map in reader.DoomMaps)
                    {
                        WADDecompiler wadDecompiler = new WADDecompiler(map, jobnum, this);
                        Entities      holyshit      = wadDecompiler.decompile();
                        MAPMaker.outputMaps(holyshit, map.MapName, map.Folder + map.WadName + "\\", map.Version);
                    }
                    break;

                default:
                    DecompilerThread.OnMessage(this, "ERROR: Unknown BSP version: " + reader.Version);
                    throw new System.Exception();                                     // Throw an exception to the exception handler to indicate it didn't work
                }
                //}
            }
            if (output != null)
            {
                //Window.setProgress(jobnum, 1, 1, "Saving...");
                if (doomMap == null)
                {
                    MAPMaker.outputMaps(output, BSPObject.MapNameNoExtension, BSPObject.Folder, BSPObject.Version);
                }
                else
                {
                    MAPMaker.outputMaps(output, doomMap.MapName, doomMap.Folder + doomMap.WadName + "\\", doomMap.Version);
                }
            }
            //Window.setProgress(jobnum, 1, 1, "Done!");
            //System.Drawing.Color tempAux = System.Drawing.Color.FromArgb(64, 192, 64);
            //Window.setProgressColor(jobnum, ref tempAux);
            DateTime end = DateTime.Now;
            DecompilerThread.OnMessage(this, "Time taken: " + (end - begin).ToString() + (char)0x0D + (char)0x0A);
            OnFinish(this, jobnum);
        } catch (System.OutOfMemoryException) {
            string st = "";
            if (openAs != mapType.TYPE_UNDEFINED)
            {
                st = "VM ran out of memory on job " + (jobnum + 1) + ". Are you using \"Open as...\" with the wrong game?" + (char)0x0D + (char)0x0A + "If not, please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry";
            }
            else
            {
                st = "VM ran out of memory on job " + (jobnum + 1) + "." + (char)0x0D + (char)0x0A + "Please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry";
            }
            //Window.setProgress(jobnum, 1, 1, "ERROR! See log!");
            //System.Drawing.Color tempAux4 = System.Drawing.Color.FromArgb(255, 128, 128);
            //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
            //Window.setProgressColor(jobnum, ref tempAux4);
            OnError(this, st);
        } catch (Exception e) {
            string st;
            if (openAs != mapType.TYPE_UNDEFINED)
            {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                st = "" + (char)0x0D + (char)0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char)0x0D + (char)0x0A + "Are you using \"Open as...\" with the wrong game?" + (char)0x0D + (char)0x0A + "If not, please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry";
            }
            else
            {
                //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.toString' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
                st = "" + (char)0x0D + (char)0x0A + "Exception caught in job " + (jobnum + 1) + ": " + e + (char)0x0D + (char)0x0A + "Please let me know on the issue tracker!" + (char)0x0D + (char)0x0A + "http://code.google.com/p/jbn-bsp-lump-tools/issues/entry";
            }

            /*System.String stackTrace = "Stack Trace: " + (char) 0x0D + (char) 0x0A;
             * StackTraceElement[] trace = e.getStackTrace();
             * for (int i = 0; i < trace.length; i++)
             * {
             *      stackTrace += (trace[i].toString() + Window.LF);
             * }
             * //UPGRADE_TODO: The equivalent in .NET for method 'java.lang.Throwable.getMessage' may return a different value. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1043'"
             * DecompilerThread.OnMessage(this, e.Message + Window.LF + stackTrace);
             * DecompilerThread.OnMessage(this, );
             * Window.setProgress(jobnum, 1, 1, "ERROR! See log!");
             * System.Drawing.Color tempAux3 = System.Drawing.Color.FromArgb(255, 128, 128);
             * //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
             * Window.setProgressColor(jobnum, ref tempAux3);*/
            OnError(this, st);
        } finally {
            doomMap   = null;
            BSPObject = null;
            BSPFile   = null;
            Thread.CurrentThread.Abort();
        }

        /*else
         * {
         *      Window.print("Job " + (jobnum + 1) + " aborted by user.");
         *      Window.print(" When: While initializing job.");
         *      DecompilerThread.OnMessage(this, );
         *      Window.setProgress(jobnum, 1, 1, "Aborted!");
         *      System.Drawing.Color tempAux5 = System.Drawing.Color.FromArgb(255, 128, 128);
         *      //UPGRADE_NOTE: ref keyword was added to struct-type parameters. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextWindowIndex'&keyword='jlca1303'"
         *      Window.setProgressColor(jobnum, ref tempAux5);
         *      SupportClass.ThreadClass.Current().Interrupt();
         * }*/
        //Window.setAbortButtonEnabled(jobnum, false);
    }
Ejemplo n.º 23
0
    // -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);
        }
    }
Ejemplo n.º 24
0
    // METHODS

    public virtual void printBSPReport()
    {
        // If there's a NullReferenceException here, the BSPReader class didn't initialize the object and therefore
        // this is either a BSP format which doesn't use that lump, or there's an error which will become apparent.
        DecompilerThread.OnMessage(this, "Internal version number: " + (int)version + " (" + version + ")");
        if (entities != null)
        {
            DecompilerThread.OnMessage(this, "Entities lump: " + entities.Length + " bytes, " + entities.Count + " items");
        }
        if (planes != null)
        {
            DecompilerThread.OnMessage(this, "Planes lump: " + planes.Length + " bytes, " + planes.Count + " items");
            if (planes.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Planes");
            }
        }
        if (textures != null)
        {
            DecompilerThread.OnMessage(this, "Texture lump: " + textures.Length + " bytes, " + textures.Count + " items");
            if (textures.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Texture");
            }
        }
        if (materials != null)
        {
            DecompilerThread.OnMessage(this, "Materials lump: " + materials.Length + " bytes, " + materials.Count + " items");
            if (materials.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Materials");
            }
        }
        if (vertices != null)
        {
            DecompilerThread.OnMessage(this, "Vertices lump: " + vertices.Length + " bytes, " + vertices.Count + " items");
            if (vertices.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Vertices");
            }
        }
        if (nodes != null)
        {
            DecompilerThread.OnMessage(this, "Nodes lump: " + nodes.Length + " bytes, " + nodes.Count + " items");
            if (nodes.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Nodes");
            }
        }
        if (texInfo != null)
        {
            DecompilerThread.OnMessage(this, "Texture info lump: " + texInfo.Length + " bytes, " + texInfo.Count + " items");
            if (texInfo.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Texture info");
            }
        }
        if (faces != null)
        {
            DecompilerThread.OnMessage(this, "Faces lump: " + faces.Length + " bytes, " + faces.Count + " items");
            if (faces.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Faces");
            }
        }
        if (leaves != null)
        {
            DecompilerThread.OnMessage(this, "Leaves lump: " + leaves.Length + " bytes, " + leaves.Count + " items");
            if (leaves.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Leaves");
            }
        }
        if (markSurfaces != null)
        {
            DecompilerThread.OnMessage(this, "Mark surfaces lump: " + markSurfaces.Length + " bytes, " + markSurfaces.Count + " items");
            if (markSurfaces.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Mark surfaces");
            }
        }
        if (edges != null)
        {
            DecompilerThread.OnMessage(this, "Edges lump: " + edges.Length + " bytes, " + edges.Count + " items");
            if (edges.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Edges");
            }
        }
        if (surfEdges != null)
        {
            DecompilerThread.OnMessage(this, "Surface Edges lump: " + surfEdges.Length + " bytes, " + surfEdges.Count + " items");
            if (surfEdges.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Surface Edges");
            }
        }
        if (models != null)
        {
            DecompilerThread.OnMessage(this, "Models lump: " + models.Length + " bytes, " + models.Count + " items");
            if (models.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Models");
            }
        }
        if (brushes != null)
        {
            DecompilerThread.OnMessage(this, "Brushes lump: " + brushes.Length + " bytes, " + brushes.Count + " items");
            if (brushes.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Brushes");
            }
        }
        if (brushSides != null)
        {
            DecompilerThread.OnMessage(this, "Brush sides lump: " + brushSides.Length + " bytes, " + brushSides.Count + " items");
            if (brushSides.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Brush sides");
            }
        }
        if (markBrushes != null)
        {
            DecompilerThread.OnMessage(this, "Mark brushes lump: " + markBrushes.Length + " bytes, " + markBrushes.Count + " items");
            if (markBrushes.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Mark brushes");
            }
        }
        if (originalFaces != null)
        {
            DecompilerThread.OnMessage(this, "Original Faces lump: " + originalFaces.Length + " bytes, " + originalFaces.Count + " items");
            if (originalFaces.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Original Faces");
            }
        }
        if (texTable != null)
        {
            DecompilerThread.OnMessage(this, "Texture index table lump: " + texTable.Length + " bytes, " + texTable.Count + " items");
            if (texTable.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Texture index table");
            }
        }
        if (texDatas != null)
        {
            DecompilerThread.OnMessage(this, "Texture data lump: " + texDatas.Length + " bytes, " + texDatas.Count + " items");
            if (texDatas.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Texture data");
            }
        }
        if (dispInfos != null)
        {
            DecompilerThread.OnMessage(this, "Displacement info lump: " + dispInfos.Length + " bytes, " + dispInfos.Count + " items");
            if (dispInfos.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Displacement info");
            }
        }
        if (dispVerts != null)
        {
            DecompilerThread.OnMessage(this, "Displacement Vertices lump: " + dispVerts.Length + " bytes, " + dispVerts.Count + " items");
            if (dispVerts.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Displacement Vertices");
            }
        }
        if (displacementTriangles != null)
        {
            DecompilerThread.OnMessage(this, "Displacement Triangle Tags lump: " + displacementTriangles.Length + " bytes, " + displacementTriangles.Count + " items");
            if (displacementTriangles.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Displacement Triangle Tags");
            }
        }
        if (staticProps != null)
        {
            DecompilerThread.OnMessage(this, "Static Props lump: " + staticProps.Length + " bytes, " + staticProps.Count + " items, " + staticProps.Dictionary.Length + " unique models");
        }
        if (cubemaps != null)
        {
            DecompilerThread.OnMessage(this, "Cubemaps lump: " + cubemaps.Length + " bytes, " + cubemaps.Count + " items");
            if (cubemaps.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Cubemaps");
            }
        }         /*
                   * if(overlays != null) {
                   * DecompilerThread.OnMessage(this, "Overlays lump: "+overlays.Length+" bytes, "+overlays.Count+" items",Settings.VERBOSITY_MAPSTATS);
                   *    if(overlays.hasFunnySize()) {
                   *            DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Overlays",Settings.VERBOSITY_WARNINGS);
                   *    }
                   * } catch(System.NullReferenceException) {
                   * }*/
    }
Ejemplo n.º 25
0
    // METHODS

    public virtual void  printBSPReport()
    {
        try {
            DecompilerThread.OnMessage(this, "Things lump: " + things.Length + " bytes, " + things.Count + " items");
            if (things.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Things");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Linedefs lump: " + linedefs.Length + " bytes, " + linedefs.Count + " items");
            if (linedefs.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Linedefs");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Sizedefs lump: " + sidedefs.Length + " bytes, " + sidedefs.Count + " items");
            if (sidedefs.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Sidedefs");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Vertices lump: " + vertices.Length + " bytes, " + vertices.Count + " items");
            if (vertices.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Vertices");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Segments lump: " + segs.Length + " bytes, " + segs.Count + " items");
            if (segs.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Segments");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Subsectors lump: " + subsectors.Length + " bytes, " + subsectors.Count + " items");
            if (subsectors.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Subsectors");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Nodes lump: " + nodes.Length + " bytes, " + nodes.Count + " items");
            if (nodes.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Nodes");
            }
        } catch (System.NullReferenceException) {
        }
        try {
            DecompilerThread.OnMessage(this, "Sectors lump: " + sectors.Length + " bytes, " + sectors.Count + " items");
            if (sectors.hasFunnySize())
            {
                DecompilerThread.OnMessage(this, "WARNING: Funny lump size in Sectors");
            }
        } catch (System.NullReferenceException) {
        }
    }
Ejemplo n.º 26
0
    // 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);
    }
Ejemplo n.º 27
0
    // -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);
        }
    }
 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("");
     }
 }
Ejemplo n.º 29
0
    // -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);
        }
    }
Ejemplo n.º 30
0
    // METHODS

    // Attempt to turn the Quake 2 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;
        }
        bool containsAreaPortals = false;

        for (int i = 0; i < BSPObject.Entities.Count; i++)
        {
            // For each entity
            //DecompilerThread.OnMessage(this, "Entity " + i + ": " + mapFile[i]["classname"]);
            // Deal with area portals.
            if (mapFile[i]["classname"].Equals("func_areaportal", StringComparison.CurrentCultureIgnoreCase))
            {
                mapFile[i].Attributes.Remove("style");
                containsAreaPortals = true;
            }
            // 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  firstBrushIndex = 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
                            if (!brushesUsed[(int)BSPObject.MarkBrushes[firstBrushIndex + k]])
                            {
                                // If the current brush has NOT been used in this entity
                                //Console.Write("Brush " + numBrshs);
                                brushesUsed[(int)BSPObject.MarkBrushes[firstBrushIndex + k]] = true;
                                Brush brush = BSPObject.Brushes[(int)BSPObject.MarkBrushes[firstBrushIndex + k]];
                                if ((brush.Contents[1] & ((sbyte)1 << 7)) == 0)
                                {
                                    decompileBrush(brush, i);                                     // Decompile the brush
                                }
                                else
                                {
                                    containsAreaPortals = true;
                                }
                                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));
            }
        }
        if (containsAreaPortals)
        {
            // If this map was found to have area portals
            int j = 0;
            for (int i = 0; i < BSPObject.Brushes.Count; i++)
            {
                // For each brush in this map
                if ((BSPObject.Brushes[i].Contents[1] & ((sbyte)1 << 7)) != 0)
                {
                    // If the brush is an area portal brush
                    for (j++; j < BSPObject.Entities.Count; j++)
                    {
                        // Find an areaportal entity
                        if (BSPObject.Entities[j]["classname"].Equals("func_areaportal", StringComparison.CurrentCultureIgnoreCase))
                        {
                            decompileBrush(BSPObject.Brushes[i], j); // Add the brush to that entity
                            break;                                   // And break out of the inner loop, but remember your place.
                        }
                    }
                    if (j == BSPObject.Entities.Count)
                    {
                        // If we're out of entities, stop this whole thing.
                        break;
                    }
                }
            }
        }
        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);
    }
Ejemplo n.º 31
0
		public Job(int id, string map, DecompilerThread runnable) {
			this.id = id;
			this.map = map;
			this.runnable = runnable;
			runnable.reportProgress += new ProgressEventHandler(updateProgress);
		}
Ejemplo n.º 32
0
 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);
     }
 }
Ejemplo n.º 33
0
	// CONSTRUCTORS
	
	// This constructor sets up everything to convert a Doom map into brushes compatible with modern map editors.
	// I don't know if this is decompiling, per se. I don't know if Doom maps were ever compiled or if they just had nodes built.
	public WADDecompiler(DoomMap doomMap, int jobnum, DecompilerThread parent)
	{
		this.doomMap = doomMap;
		this.jobnum = jobnum;
		this.parent = parent;
	}
    // 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);
    }