Ejemplo n.º 1
0
    // The inspiration for this is the BSPSource source code. It's not a direct copy but does essentially
    // the same thing as the algorithm to "create a prism back", and isn't as neatly written.
    public static MAPBrush createBrushFromWind(Vector3D[] froms, Vector3D[] tos, string texture, string backtex, TexInfo scaling)
    {
        Vector3D[]     planepts = new Vector3D[3];
        MAPBrushSide[] sides    = new MAPBrushSide[froms.Length + 2];      // Each edge, plus a front and back side
        planepts[0] = froms[0];
        planepts[1] = tos[0];
        planepts[2] = tos[1];
        Plane    plane         = new Plane(planepts);
        Vector3D reverseNormal = plane.Normal;

        sides[0] = new MAPBrushSide(planepts, texture, scaling.SAxis.Point, scaling.SShift, scaling.TAxis.Point, scaling.TShift, 0, 1, 1, 0, "wld_lightmap", 16, 0);

        Vector3D[] backplanepts = new Vector3D[3];
        backplanepts[0] = froms[0] - (reverseNormal);
        backplanepts[1] = tos[1] - (reverseNormal);
        backplanepts[2] = tos[0] - (reverseNormal);
        Plane backplane = new Plane(backplanepts);

        Vector3D[] backaxes = TexInfo.textureAxisFromPlane(backplane);
        sides[1] = new MAPBrushSide(backplane, backtex, backaxes[0].Point, 0, backaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);

        for (int i = 0; i < froms.Length; i++)
        {
            // each edge
            Vector3D[] sideplanepts = new Vector3D[3];
            sideplanepts[0] = froms[i];
            sideplanepts[1] = tos[i];
            sideplanepts[2] = froms[i] + (reverseNormal);
            Plane      sideplane = new Plane(sideplanepts);
            Vector3D[] sideaxes  = TexInfo.textureAxisFromPlane(sideplane);
            sides[i + 2] = new MAPBrushSide(sideplane, backtex, sideaxes[0].Point, 0, sideaxes[1].Point, 0, 0, 1, 1, 0, "wld_lightmap", 16, 0);
        }

        return(new MAPBrush(sides, 0, 0, false));
    }
Ejemplo n.º 2
0
 private string brushSideToString(MAPBrushSide inputData)
 {
     try
     {
         Vector3D[] triangle      = inputData.Triangle;
         string     texture       = inputData.Texture;
         Vector3D   textureS      = inputData.TextureS;
         Vector3D   textureT      = inputData.TextureT;
         double     textureShiftS = inputData.TextureShiftS;
         double     textureShiftT = inputData.TextureShiftT;
         float      texRot        = inputData.TexRot;
         double     texScaleX     = inputData.TexScaleX;
         double     texScaleY     = inputData.TexScaleY;
         int        flags         = inputData.Flags;
         string     material      = inputData.Material;
         double     lgtScale      = inputData.LgtScale;
         double     lgtRot        = inputData.LgtRot;
         if (Double.IsInfinity(texScaleX) || Double.IsNaN(texScaleX))
         {
             texScaleX = 1;
         }
         if (Double.IsInfinity(texScaleY) || Double.IsNaN(texScaleY))
         {
             texScaleY = 1;
         }
         if (Double.IsInfinity(textureShiftS) || Double.IsNaN(textureShiftS))
         {
             textureShiftS = 0;
         }
         if (Double.IsInfinity(textureShiftT) || Double.IsNaN(textureShiftT))
         {
             textureShiftT = 0;
         }
         if (Double.IsInfinity(textureS.X) || Double.IsNaN(textureS.X) || Double.IsInfinity(textureS.Y) || Double.IsNaN(textureS.Y) || Double.IsInfinity(textureS.Z) || Double.IsNaN(textureS.Z))
         {
             textureS = TexInfo.textureAxisFromPlane(inputData.Plane)[0];
         }
         if (Double.IsInfinity(textureT.X) || Double.IsNaN(textureT.X) || Double.IsInfinity(textureT.Y) || Double.IsNaN(textureT.Y) || Double.IsInfinity(textureT.Z) || Double.IsNaN(textureT.Z))
         {
             textureT = TexInfo.textureAxisFromPlane(inputData.Plane)[1];
         }
         if (Settings.roundNums)
         {
             return("( " + Math.Round(triangle[0].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[0].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[0].Z, 6, MidpointRounding.AwayFromZero) + " ) " +
                    "( " + Math.Round(triangle[1].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[1].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[1].Z, 6, MidpointRounding.AwayFromZero) + " ) " +
                    "( " + Math.Round(triangle[2].X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[2].Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(triangle[2].Z, 6, MidpointRounding.AwayFromZero) + " ) " +
                    texture +
                    " [ " + Math.Round(textureS.X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureS.Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureS.Z, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureShiftS, MidpointRounding.AwayFromZero) + " ]" +
                    " [ " + Math.Round(textureT.X, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureT.Y, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureT.Z, 6, MidpointRounding.AwayFromZero) + " " + Math.Round(textureShiftT, MidpointRounding.AwayFromZero) + " ] " +
                    Math.Round(texRot, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(texScaleX, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(texScaleY, 4, MidpointRounding.AwayFromZero) + " " + flags + " " + material + " [ " + Math.Round(lgtScale, 4, MidpointRounding.AwayFromZero) + " " + Math.Round(lgtRot, 4, MidpointRounding.AwayFromZero) + " ]");
         }
         else
         {
             return("( " + triangle[0].X + " " + triangle[0].Y + " " + triangle[0].Z + " ) " + "( " + triangle[1].X + " " + triangle[1].Y + " " + triangle[1].Z + " ) " + "( " + triangle[2].X + " " + triangle[2].Y + " " + triangle[2].Z + " ) " + texture + " [ " + textureS.X + " " + textureS.Y + " " + textureS.Z + " " + textureShiftS + " ]" + " [ " + textureT.X + " " + textureT.Y + " " + textureT.Z + " " + textureShiftT + " ] " + texRot + " " + texScaleX + " " + texScaleY + " " + flags + " " + material + " [ " + lgtScale + " " + lgtRot + " ]");
         }
     }
     catch (System.NullReferenceException)
     {
         Console.WriteLine("WARNING: Side with bad data! Not exported!");
         return("");
     }
 }
 private string brushSideToString(MAPBrushSide inputData, bool isDetail)
 {
     try {
         Vector3D[] triangle      = inputData.Triangle;
         string     texture       = inputData.Texture;
         Vector3D   textureS      = inputData.TextureS;
         Vector3D   textureT      = inputData.TextureT;
         double     textureShiftS = inputData.TextureShiftS;
         double     textureShiftT = inputData.TextureShiftT;
         float      texRot        = inputData.TexRot;
         double     texScaleX     = inputData.TexScaleX;
         double     texScaleY     = inputData.TexScaleY;
         int        flags         = inputData.Flags;
         string     material      = inputData.Material;
         double     lgtScale      = inputData.LgtScale;
         double     lgtRot        = inputData.LgtRot;
         string     temp          = "";
         // Correct textures here
         try
         {
             if (texture.Substring(0, (9) - (0)).ToUpper().Equals("textures/".ToUpper()))
             {
                 texture = texture.Substring(9);
             }
         }
         catch (System.ArgumentOutOfRangeException)
         {
             ;
         }
         if (BSPVersion == mapType.TYPE_NIGHTFIRE || BSPVersion == mapType.TYPE_DOOM || BSPVersion == mapType.TYPE_HEXEN)
         {
             if (texture.ToUpper().Equals("special/nodraw".ToUpper()) || texture.ToUpper().Equals("special/null".ToUpper()))
             {
                 texture = "common/nodraw";
             }
             else
             {
                 if (texture.ToUpper().Equals("special/clip".ToUpper()))
                 {
                     texture = "common/clip";
                 }
                 else
                 {
                     if (texture.ToUpper().Equals("special/sky".ToUpper()))
                     {
                         texture = "common/skyportal";
                     }
                     else
                     {
                         if (texture.ToUpper().Equals("special/trigger".ToUpper()))
                         {
                             texture = "common/trigger";
                         }
                         else
                         {
                             if (texture.ToUpper().Equals("special/playerclip".ToUpper()))
                             {
                                 texture = "common/playerclip";
                             }
                             else
                             {
                                 if (texture.ToUpper().Equals("special/npcclip".ToUpper()) || texture.ToUpper().Equals("special/enemyclip".ToUpper()))
                                 {
                                     texture = "common/tankclip";
                                 }
                             }
                         }
                     }
                 }
             }
         }
         else
         {
             if (BSPVersion == mapType.TYPE_QUAKE2)
             {
                 try
                 {
                     if (texture.ToUpper().Equals("special/hint".ToUpper()))
                     {
                         texture = "common/hint";
                     }
                     else
                     {
                         if (texture.ToUpper().Equals("special/skip".ToUpper()))
                         {
                             texture = "common/skip";
                         }
                         else
                         {
                             if (texture.ToUpper().Equals("special/sky".ToUpper()))
                             {
                                 texture = "common/skyportal";
                             }
                             else
                             {
                                 if (texture.Substring(texture.Length - 8).ToUpper().Equals("/trigger".ToUpper()))
                                 {
                                     texture = "common/trigger";
                                 }
                                 else
                                 {
                                     if (texture.Substring(texture.Length - 5).ToUpper().Equals("/clip".ToUpper()))
                                     {
                                         texture = "common/clip";
                                     }
                                 }
                             }
                         }
                     }
                 }
                 catch (System.ArgumentOutOfRangeException e)
                 {
                     ;
                 }
             }
             else
             {
                 if (BSPVersion == mapType.TYPE_SOURCE17 || BSPVersion == mapType.TYPE_SOURCE18 || BSPVersion == mapType.TYPE_SOURCE19 || BSPVersion == mapType.TYPE_SOURCE20 || BSPVersion == mapType.TYPE_SOURCE21 || BSPVersion == mapType.TYPE_SOURCE22 || BSPVersion == mapType.TYPE_SOURCE23 || BSPVersion == mapType.TYPE_DMOMAM || BSPVersion == mapType.TYPE_VINDICTUS || BSPVersion == mapType.TYPE_TACTICALINTERVENTION)
                 {
                     try
                     {
                         if (texture.Substring(0, (5) - (0)).ToUpper().Equals("maps/".ToUpper()))
                         {
                             texture = texture.Substring(5);
                             for (int i = 0; i < texture.Length; i++)
                             {
                                 if (texture[i] == '/')
                                 {
                                     texture = texture.Substring(i + 1);
                                     break;
                                 }
                             }
                         }
                     }
                     catch (System.ArgumentOutOfRangeException e)
                     {
                         ;
                     }
                     // Find cubemap textures
                     int  numUnderscores = 0;
                     bool validnumber    = false;
                     for (int i = texture.Length - 1; i > 0; i--)
                     {
                         if (texture[i] <= '9' && texture[i] >= '0')
                         {
                             // Current is a number, start building string
                             validnumber = true;
                         }
                         else
                         {
                             if (texture[i] == '-')
                             {
                                 // Current is a minus sign (-).
                                 if (!validnumber)
                                 {
                                     break;                                         // Make sure there's a number to add the minus sign to. If not, kill the loop.
                                 }
                             }
                             else
                             {
                                 if (texture[i] == '_')
                                 {
                                     // Current is an underscore (_)
                                     if (validnumber)
                                     {
                                         // Make sure there is a number in the current string
                                         numUnderscores++;                                             // before moving on to the next one.
                                         validnumber = false;
                                         if (numUnderscores == 3)
                                         {
                                             // If we've got all our numbers
                                             texture = texture.Substring(0, (i) - (0));             // Cut the texture string
                                             break;                                                 // Kill the loop, we're done
                                         }
                                     }
                                     else
                                     {
                                         // No number after the underscore
                                         break;
                                     }
                                 }
                                 else
                                 {
                                     // Not an acceptable character
                                     break;
                                 }
                             }
                         }
                     }
                 }
             }
         }
         if (Double.IsInfinity(texScaleX) || Double.IsNaN(texScaleX))
         {
             texScaleX = 1;
         }
         if (Double.IsInfinity(texScaleY) || Double.IsNaN(texScaleY))
         {
             texScaleY = 1;
         }
         if (Double.IsInfinity(textureShiftS) || Double.IsNaN(textureShiftS))
         {
             textureShiftS = 0;
         }
         if (Double.IsInfinity(textureShiftT) || Double.IsNaN(textureShiftT))
         {
             textureShiftT = 0;
         }
         if (Double.IsInfinity(textureS.X) || Double.IsNaN(textureS.X) || Double.IsInfinity(textureS.Y) || Double.IsNaN(textureS.Y) || Double.IsInfinity(textureS.Z) || Double.IsNaN(textureS.Z))
         {
             textureS = TexInfo.textureAxisFromPlane(inputData.Plane)[0];
         }
         if (Double.IsInfinity(textureT.X) || Double.IsNaN(textureT.X) || Double.IsInfinity(textureT.Y) || Double.IsNaN(textureT.Y) || Double.IsInfinity(textureT.Z) || Double.IsNaN(textureT.Z))
         {
             textureT = TexInfo.textureAxisFromPlane(inputData.Plane)[1];
         }
         if (Settings.roundNums)
         {
             temp = "( " + MAPMaker.Round(triangle[0].X, 6) +
                    " " + MAPMaker.Round(triangle[0].Y, 6) +
                    " " + MAPMaker.Round(triangle[0].Z, 6) + " ) " +
                    "( " + MAPMaker.Round(triangle[1].X, 6) +
                    " " + MAPMaker.Round(triangle[1].Y, 6) +
                    " " + MAPMaker.Round(triangle[1].Z, 6) + " ) " +
                    "( " + MAPMaker.Round(triangle[2].X, 6) +
                    " " + MAPMaker.Round(triangle[2].Y, 6) +
                    " " + MAPMaker.Round(triangle[2].Z, 6) + " ) " +
                    texture + " " + System.Math.Floor(textureShiftS) + " " + System.Math.Floor(textureShiftT) + " " +
                    MAPMaker.FormattedRound(texRot, 2, "######0.00") + " " +
                    MAPMaker.Round(texScaleX, 6) + " " +
                    MAPMaker.Round(texScaleY, 6) + " " + flags + " 0 0 ";
         }
         else
         {
             temp = "( " + triangle[0].X + " " + triangle[0].Y + " " + triangle[0].Z + " ) " + "( " + triangle[1].X + " " + triangle[1].Y + " " + triangle[1].Z + " ) " + "( " + triangle[2].X + " " + triangle[2].Y + " " + triangle[2].Z + " ) " + texture + " " + textureShiftS + " " + textureShiftT + " " + texRot + " " + texScaleX + " " + texScaleY + " " + flags + " 0 0 ";
         }
         if (isDetail)
         {
             temp += "+surfaceparm detail ";
         }
         return(temp);
     }
     catch (System.NullReferenceException e)
     {
         DecompilerThread.OnMessage(this, "WARNING: Side with bad data! Not exported!");
         return("");
     }
 }
    // -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);
        }
    }
Ejemplo n.º 5
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.º 6
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);
        }
    }
    // 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);
    }
 public virtual TexInfo createPerpTexInfo(Plane in_Renamed)
 {
     Vector3D[] axes = TexInfo.textureAxisFromPlane(in_Renamed);
     return(new TexInfo(axes[0], 0, axes[1], 0, 0, BSPObject.findTexDataWithTexture("tools/toolsclip")));
 }
    // -decompileBrush38(Brush, int, boolean)
    // Decompiles the Brush and adds it to entitiy #currentEntity as .MAP data.
    private void decompileBrush(Brush brush, int currentEntity)
    {
        Vector3D origin    = mapFile[currentEntity].Origin;
        int      firstSide = brush.FirstSide;
        int      numSides  = brush.NumSides;

        MAPBrushSide[] brushSides = new MAPBrushSide[numSides];
        bool           isDetail   = false;

        if (currentEntity == 0 && !Settings.noDetail && (brush.Contents[3] & ((sbyte)1 << 3)) != 0)
        {
            isDetail = true;
        }
        MAPBrush mapBrush = new MAPBrush(numBrshs, currentEntity, isDetail);

        if (currentEntity == 0 && !Settings.noWater && (brush.Contents[0] & ((sbyte)1 << 5)) != 0)
        {
            mapBrush.Water = true;
        }
        //DecompilerThread.OnMessage(this, ": " + numSides + " sides, detail: " + isDetail);
        for (int i = 0; i < numSides; i++)
        {
            // For each side of the brush
            BrushSide currentSide = BSPObject.BrushSides[firstSide + i];
            if (currentSide.isBevel() == 0)
            {
                // Bevel sides are evil
                Vector3D[] plane        = new Vector3D[3];                     // Three points define a plane. All I have to do is find three points on that plane.
                Plane      currentPlane = BSPObject.Planes[currentSide.Plane]; // To find those three points, I must extrapolate from planes until I find a way to associate faces with brushes
                bool       isDuplicate  = false;                               /* TODO: We sure don't want duplicate planes (though this is already handled by the MAPBrush class). Make sure neither checked side is bevel.
                                                                                * for(int j=i+1;j<numSides;j++) { // For each subsequent side of the brush
                                                                                * if(currentPlane.equals(BSPObject.Planes.getPlane(BSPObject.getBrushSides()[firstSide+j).getPlane()))) {
                                                                                * DecompilerThread.OnMessage(this, "WARNING: Duplicate planes in a brush, sides "+i+" and "+j,Settings.VERBOSITY_WARNINGS);
                                                                                * isDuplicate=true;
                                                                                * }
                                                                                * }*/
                if (!isDuplicate)
                {
                    TexInfo currentTexInfo = null;
                    string  texture        = "tools/toolsclip";
                    if (currentSide.Texture > -1)
                    {
                        currentTexInfo = BSPObject.TexInfo[currentSide.Texture];
                    }
                    else
                    {
                        int dataIndex = BSPObject.findTexDataWithTexture("tools/toolsclip");
                        if (dataIndex >= 0)
                        {
                            currentTexInfo = new TexInfo(new Vector3D(0, 0, 0), 0, new Vector3D(0, 0, 0), 0, 0, dataIndex);
                        }
                    }
                    if (currentTexInfo != null)
                    {
                        SourceTexData currentTexData;
                        if (currentTexInfo.Texture >= 0)
                        {
                            // I've only found one case where this is a problem: c2a3a in HL Source. Don't know why.
                            currentTexData = BSPObject.TexDatas[currentTexInfo.Texture];
                            texture        = BSPObject.Textures.getTextureAtOffset((uint)BSPObject.TexTable[currentTexData.StringTableIndex]);
                        }
                        else
                        {
                            texture = "tools/toolsskip";
                        }
                    }
                    double[] textureU      = new double[3];
                    double[] textureV      = new double[3];
                    double   textureShiftU = 0;
                    double   textureShiftV = 0;
                    double   texScaleU     = 1;
                    double   texScaleV     = 1;
                    // Get the lengths of the axis vectors
                    if ((texture.Length > 6 && texture.Substring(0, (6) - (0)).ToUpper().Equals("tools/".ToUpper())) || currentTexInfo == null)
                    {
                        // Tools textured faces do not maintain their own texture axes. Therefore, an arbitrary axis is
                        // used in the compiled map. When decompiled, these axes might smear the texture on the face. Fix that.
                        Vector3D[] axes = TexInfo.textureAxisFromPlane(currentPlane);
                        textureU = axes[0].Point;
                        textureV = axes[1].Point;
                    }
                    else
                    {
                        double SAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.SAxis.X, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.SAxis.Z, 2));
                        double TAxisLength = System.Math.Sqrt(System.Math.Pow((double)currentTexInfo.TAxis.X, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Y, 2) + System.Math.Pow((double)currentTexInfo.TAxis.Z, 2));
                        // In compiled maps, shorter vectors=longer textures and vice versa. This will convert their lengths back to 1. We'll use the actual scale values for length.
                        texScaleU   = (1 / SAxisLength);                       // Let's use these values using the lengths of the U and V axes we found above.
                        texScaleV   = (1 / TAxisLength);
                        textureU[0] = ((double)currentTexInfo.SAxis.X / SAxisLength);
                        textureU[1] = ((double)currentTexInfo.SAxis.Y / SAxisLength);
                        textureU[2] = ((double)currentTexInfo.SAxis.Z / SAxisLength);
                        double originShiftU = (((double)currentTexInfo.SAxis.X / SAxisLength) * origin[X] + ((double)currentTexInfo.SAxis.Y / SAxisLength) * origin[Y] + ((double)currentTexInfo.SAxis.Z / SAxisLength) * origin[Z]) / texScaleU;
                        //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'"
                        textureShiftU = (double)currentTexInfo.SShift - originShiftU;
                        textureV[0]   = ((double)currentTexInfo.TAxis.X / TAxisLength);
                        textureV[1]   = ((double)currentTexInfo.TAxis.Y / TAxisLength);
                        textureV[2]   = ((double)currentTexInfo.TAxis.Z / TAxisLength);
                        double originShiftV = (((double)currentTexInfo.TAxis.X / TAxisLength) * origin[X] + ((double)currentTexInfo.TAxis.Y / TAxisLength) * origin[Y] + ((double)currentTexInfo.TAxis.Z / TAxisLength) * origin[Z]) / texScaleV;
                        //UPGRADE_WARNING: Data types in Visual C# might be different.  Verify the accuracy of narrowing conversions. "ms-help://MS.VSCC.v80/dv_commoner/local/redirect.htm?index='!DefaultContextSettingsIndex'&keyword='jlca1042'"
                        textureShiftV = (double)currentTexInfo.TShift - originShiftV;
                    }
                    float  texRot   = 0;               // In compiled maps this is calculated into the U and V axes, so set it to 0 until I can figure out a good way to determine a better value.
                    int    flags    = 0;               // Set this to 0 until we can somehow associate faces with brushes
                    string material = "wld_lightmap";  // Since materials are a NightFire only thing, set this to a good default
                    double lgtScale = 16;              // These values are impossible to get from a compiled map since they
                    double lgtRot   = 0;               // are used by RAD for generating lightmaps, then are discarded, I believe.
                    brushSides[i] = new MAPBrushSide(currentPlane, texture, textureU, textureShiftU, textureV, textureShiftV, texRot, texScaleU, texScaleV, flags, material, lgtScale, lgtRot);
                    mapBrush.add(brushSides[i]);
                }
            }
        }

        if (!Settings.skipPlaneFlip)
        {
            if (mapBrush.hasBadSide())
            {
                // If there's a side that might be backward
                if (mapBrush.hasGoodSide())
                {
                    // If there's a side that is forward
                    mapBrush = MAPBrush.SimpleCorrectPlanes(mapBrush);
                    numSimpleCorrects++;
                    if (Settings.calcVerts)
                    {
                        // This is performed in advancedcorrect, so don't use it if that's happening
                        try
                        {
                            mapBrush = MAPBrush.CalcBrushVertices(mapBrush);
                        }
                        catch (System.NullReferenceException)
                        {
                            DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + "");
                        }
                    }
                }
                else
                {
                    // If no forward side exists
                    try
                    {
                        mapBrush = MAPBrush.AdvancedCorrectPlanes(mapBrush);
                        numAdvancedCorrects++;
                    }
                    catch (System.ArithmeticException)
                    {
                        DecompilerThread.OnMessage(this, "WARNING: Plane correct returned 0 triangles for entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + "");
                    }
                }
            }
            else
            {
                numGoodBrushes++;
            }
        }
        else
        {
            if (Settings.calcVerts)
            {
                // This is performed in advancedcorrect, so don't use it if that's happening
                try
                {
                    mapBrush = MAPBrush.CalcBrushVertices(mapBrush);
                }
                catch (System.NullReferenceException)
                {
                    DecompilerThread.OnMessage(this, "WARNING: Brush vertex calculation failed on entity " + mapBrush.Entnum + " brush " + mapBrush.Brushnum + "");
                }
            }
        }

        // This adds the brush we've been finding and creating to
        // the current entity as an attribute. The way I've coded
        // this whole program and the entities parser, this shouldn't
        // cause any issues at all.
        if (Settings.brushesToWorld)
        {
            mapBrush.Water = false;
            mapFile[0].Brushes.Add(mapBrush);
        }
        else
        {
            mapFile[currentEntity].Brushes.Add(mapBrush);
        }
    }