예제 #1
0
        public void EntityMoveToSide()
        {
            Entity e = GetSelectedEntity();

            if (e != null && selected_segment > -1 && selected_side > -1)
            {
                Side side = GetSelectedSide();

                //If moving a door, point the side to the door & set the split plane (if not already split), and clear door's old side
                if (e.Type == EntityType.DOOR)
                {
                    //Clear door from old segment side
                    foreach (Side s in this.segment[e.m_segnum].side)
                    {
                        if (s.Door == e.num)
                        {
                            s.Door = -1;
                            break;
                        }
                    }
                    Debug.Assert(side.Door == -1);
                    side.Door = e.num;
                    if (side.chunk_plane_order == -1)
                    {
                        side.chunk_plane_order = 0;
                    }
                }

                e.SetPosition(side.FindCenterBetter(), selected_segment);
                e.FaceDirection(side.FindNormal());
            }
        }
예제 #2
0
        public void UpdateClipNormal(int idx)
        {
            Vector3 v;
            Side    s2;

            switch (clip[idx])
            {
            case DecalClip.ADJACENT:
                // Average of this normal and the next non-neighbor side (falls back to this segment if no neighbor, which is the same as AVERAGE)
                s2 = side.FindAdjacentSideOtherSegment(idx);
                v  = s2.FindNormal();
                v  = v + side.FindNormal();
                v.Normalize();                         // Will always be valid unless you have an infinitely thin wall (in which case that's bad anyway)

                clip_normal[idx] = v;
                break;

            case DecalClip.AVERAGE:
                // Average of this normal and the adjacent side normal
                s2 = side.FindAdjacentSideSameSegment(idx);
                v  = s2.FindNormal();
                v  = v + side.FindNormal();
                v.Normalize();                         // Will always be valid because the segment can't have two coincident sides

                clip_normal[idx] = v;
                break;

            case DecalClip.WHOLE:                     // This could be changed to same as segment if it doesn't work as desired, or could add second WHOLE variant
            case DecalClip.PERP:
                // The side normal
                clip_normal[idx] = side.FindNormal();
                break;

            case DecalClip.SEGMENT:
                // The edge direction away (in the adjacent side)
                v = side.FindAdjacentSideEdgeDirAway(idx);

                clip_normal[idx] = v;
                break;

            default:
                clip_normal[idx] = Vector3.Zero;
                break;
            }
        }
예제 #3
0
 public Vector3 GetSelectedSideNormal()
 {
     if (selected_side > -1 && selected_segment > -1)
     {
         Side s = segment[selected_segment].side[selected_side];
         return(s.FindNormal());
     }
     else
     {
         editor.AddOutputText("WARNING: No selected segment side");
         return(Vector3.UnitZ);
     }
 }
예제 #4
0
 public void GetSelectedSidePosAndNormal(out Vector3 pos, out Vector3 normal)
 {
     if (selected_side > -1 && selected_segment > -1)
     {
         Side s = segment[selected_segment].side[selected_side];
         pos    = s.FindCenter();
         normal = s.FindNormal();
     }
     else
     {
         editor.AddOutputText("WARNING: No selected segment side");
         pos    = Vector3.Zero;
         normal = Vector3.Zero;
     }
 }
        //Returns segnum, or -1
        public int InsertSegmentSelectedSide(bool regular = false)
        {
            if (selected_side > -1 && selected_segment > -1)
            {
                Side s = segment[selected_segment].side[selected_side];
                if (s.segment.neighbor[selected_side] < 0)
                {
                    Vector3 side_normal = -s.FindNormal();
                    Vector3 side_right  = s.FindBestEdgeDir();                    // s.FindEdgeDir(0);
                    Vector3 side_up     = Vector3.Cross(side_normal, side_right).Normalized();
                    Vector3 side_center = s.FindCenter();

                    int idx_new = InsertSegmentBasic(s, side_center, side_normal, side_right, side_up, regular, editor.CurrExtrudeLength);

                    segment[idx_new].CopyTexturesAndDecalsFromSegmentAtBack(segment[selected_segment], selected_side);
                    s.DisableDecals();

                    // Tag the two segments (for refreshing decals)
                    UnTagAllSegments();
                    segment[idx_new].m_tag = true;
                    s.segment.m_tag        = true;

                    // Select the new cube (depending on the option)
                    if (editor.ShouldInsertAdvance)
                    {
                        selected_segment = idx_new;
                        //selected_side = (int)SideOrder.FRONT;
                    }

                    return(idx_new);
                }
                else
                {
                    // Already has a neighbor
                }
            }
            else
            {
                // Nothing selected
            }

            return(-1);
        }
        public void FindBaseAttributes(Decal d)
        {
            Side s = d.side;

            m_base_normal = s.FindNormal();

            // Center position
            switch (d.align)
            {
            case DecalAlign.TEXTURE:
                m_base_pos = s.FindUVCenterIn3D();
                break;

            case DecalAlign.CENTER:
                m_base_pos = s.FindCenter();
                break;

            case DecalAlign.EDGE_RIGHT:
            case DecalAlign.EDGE_DOWN:
            case DecalAlign.EDGE_LEFT:
            case DecalAlign.EDGE_UP:
                m_base_pos = s.FindEdgeCenter((int)d.align - (int)DecalAlign.EDGE_RIGHT);
                break;
            }

            m_base_rvec = Vector3.Zero;

            // Up vector
            switch (d.align)
            {
            case DecalAlign.TEXTURE:
                m_base_uvec = s.FindUVUpVector();
                break;

            case DecalAlign.CENTER:
                m_base_uvec = s.FindBestEdgeDir();
                break;

            case DecalAlign.EDGE_RIGHT:
            case DecalAlign.EDGE_DOWN:
            case DecalAlign.EDGE_LEFT:
            case DecalAlign.EDGE_UP:
                m_base_rvec = -s.FindEdgeDir((int)d.align - (int)DecalAlign.EDGE_RIGHT);
                m_base_uvec = Vector3.Cross(m_base_normal, m_base_rvec);
                break;
            }

            // Find the right vec for cases we haven't already
            if (m_base_rvec == Vector3.Zero)
            {
                m_base_rvec = Vector3.Cross(m_base_uvec, m_base_normal);
            }

            // Apply the rotation of the decal properties to the Up and Right Vector
            Matrix4 vec_rot = Matrix4.CreateFromAxisAngle(m_base_normal, d.RotationAngle());

            m_base_uvec = Vector3.TransformNormal(m_base_uvec, vec_rot);
            m_base_rvec = Vector3.TransformNormal(m_base_rvec, vec_rot);

            // Base rotation
            m_base_rot = Matrix4.Transpose(Matrix4.LookAt(Vector3.Zero, m_base_normal, m_base_uvec));
        }
        public List <Tuple <int, int> > InsertMarkedSidesMulti(int extrude_length, Side s)
        {
            Vector3 side_normal = -s.FindNormal();
            Vector3 side_right, side_up, side_center;

            // Find the list of marked sides
            List <Side> side_list = new List <Side>();

            // Tag the segments (for refreshing decals)
            UnTagAllSegments();

            // Get the list of marked sides
            for (int i = 0; i < MAX_SEGMENTS; i++)
            {
                if (!segment[i].Visible)
                {
                    continue;
                }
                for (int j = 0; j < Segment.NUM_SIDES; j++)
                {
                    if (segment[i].neighbor[j] < 0)
                    {
                        if (segment[i].side[j].marked)
                        {
                            side_list.Add(segment[i].side[j]);
                            segment[i].m_tag = true;
                        }
                    }
                }
            }

            int idx_new;

            // Create a new segment for each marked side
            List <Tuple <int, int> > res = new List <Tuple <int, int> >();

            for (int i = 0; i < side_list.Count; i++)
            {
                side_right  = side_list[i].FindBestEdgeDir();
                side_up     = Vector3.Cross(side_normal, side_right).Normalized();
                side_center = side_list[i].FindCenter();

                idx_new = InsertSegmentBasic(side_list[i], side_center, side_normal, side_right, side_up, false, extrude_length);

                segment[idx_new].CopyTexturesAndDecalsFromSegmentAtBack(side_list[i].segment, side_list[i].num);
                side_list[i].DisableDecals();

                segment[idx_new].m_tag = true;

                // Mark the new side and unmark the old
                side_list[i].marked = false;
                segment[idx_new].side[side_list[i].num].marked = true;
                res.Add(Tuple.Create(idx_new, side_list[i].num));

                // Select the segment if it was the selected one
                if (side_list[i].num == selected_side && side_list[i].segment.num == selected_segment)
                {
                    selected_segment = idx_new;
                }
            }

            return(res);
        }
        public static void DetermineLevelChunking(Level level)
        {
            m_level      = level;
            m_num_chunks = 0;

            int num_segments = 0;

            SegmentType[] SegmentTypes = null;
            if (EnableAutomaticChunking)
            {
                SegmentTypes = new SegmentType[Level.MAX_SEGMENTS];
            }

            //Clear out chunk count array
            m_chunk_size.Init(0);

            if (!EnableAutomaticChunking)
            {
                //No automatic chunking, so put everything in one chunk
                foreach (int segmentIndex in level.EnumerateAliveSegmentIndices())
                {
                    level.segment[segmentIndex].m_chunk_num = 0;
                    num_segments++;
                }
                m_chunk_size[0] = num_segments;
                m_num_chunks    = 1;
            }
            else
            {
                //Loop through segment, assigning each to a chunk
                foreach (int segmentIndex in level.EnumerateAliveSegmentIndices())
                {
                    var segmentData = level.segment[segmentIndex];
                    num_segments++;

                    //Count the number of portals
                    int num_portals = 0;
                    for (int sideIdx = 0; sideIdx < 6; ++sideIdx)
                    {
                        if (segmentData.neighbor[sideIdx] != -1)
                        {
                            num_portals++;
                        }
                    }

                    //Figure out what kind of segment; default to complex
                    SegmentTypes[segmentIndex] = SegmentType.Complex;
                    if (num_portals == 1)
                    {
                        SegmentTypes[segmentIndex] = SegmentType.Single;
                    }
                    else if (num_portals == 2)
                    {
                        //If two portals, see if they're opposite
                        if (((segmentData.neighbor[0] != -1) && (segmentData.neighbor[2] != -1)) ||
                            ((segmentData.neighbor[1] != -1) && (segmentData.neighbor[3] != -1)) ||
                            ((segmentData.neighbor[4] != -1) && (segmentData.neighbor[5] != -1)))
                        {
                            //Ok, we've got two opposite sides.
                            SegmentTypes[segmentIndex] = SegmentType.Connector;
                        }
                    }

                    //Now decide what to do with this segment
                    int chunk_num = -1;
                    for (int sideIdx = 0; sideIdx < 6; ++sideIdx)
                    {
                        if (segmentData.neighbor[sideIdx] != -1)
                        {
                            int other = segmentData.neighbor[sideIdx];

                            //Only look at lower-numbered segments, which will already have type set
                            if (other < segmentIndex)
                            {
                                //Join with the other if it's the same as us, or if we're a signel or it's a single
                                if ((SegmentTypes[other] == SegmentTypes[segmentIndex]) || (SegmentTypes[segmentIndex] == SegmentType.Single) || (SegmentTypes[other] == SegmentType.Single))
                                {
                                    int other_chunk_num = level.segment[other].m_chunk_num;

                                    //We should join with the other segment.  See if we're already in a chunk
                                    if (chunk_num == -1)
                                    {
                                        //We're not in a chunk, so join with the other
                                        chunk_num = other_chunk_num;
                                    }
                                    else
                                    {
                                        //We're already in a chunk, so move all segments from other chunk to our chunk
                                        for (int t = 0; t < segmentIndex; t++)
                                        {
                                            if (level.segment[t].Alive)
                                            {
                                                if (level.segment[t].m_chunk_num == other_chunk_num)
                                                {
                                                    level.segment[t].m_chunk_num = chunk_num;
                                                    m_chunk_size[other_chunk_num]--;
                                                    m_chunk_size[chunk_num]++;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    //If we didn't find a chunk to join, start a new one
                    if (chunk_num == -1)
                    {
                        chunk_num = m_num_chunks++;
                    }

                    segmentData.m_chunk_num = chunk_num;
                    m_chunk_size[chunk_num]++;
                }

                //Now, go through and split up any overly big connector chunks
                //Sorry that this code is so ugly and hard to follow
                for (int chunknum = 0; chunknum < m_num_chunks; chunknum++)
                {
                    //If more than five, split
                    if (m_chunk_size[chunknum] > MAX_CONNECTOR_CHUNK_SIZE)
                    {
                        //Determine if this is a connector chunk, and if so find terminal segment
                        Segment seg = null;
                        int     segnum, sidenum = -1, other_segnum = -1;
                        for (segnum = 0; segnum < Level.MAX_SEGMENTS; segnum++)
                        {
                            seg = level.segment[segnum];
                            if (seg.Alive && (seg.m_chunk_num == chunknum))
                            {
                                //If this is a complex chunk, bail
                                if (SegmentTypes[segnum] == SegmentType.Complex)
                                {
                                    break;
                                }

                                //It's a connector; see if this one is the terminus
                                if (SegmentTypes[segnum] == SegmentType.Connector)
                                {
                                    for (sidenum = 0; sidenum < 6; sidenum++)
                                    {
                                        other_segnum = seg.neighbor[sidenum];
                                        if (other_segnum != -1)
                                        {
                                            if (SegmentTypes[other_segnum] != SegmentType.Connector)                                                    //Connected to something else, so this is terminus
                                            {
                                                break;
                                            }
                                        }
                                    }
                                }
                                if (sidenum < 6)
                                {
                                    break;
                                }
                            }
                        }
                        if ((segnum < Level.MAX_SEGMENTS) && (SegmentTypes[segnum] == SegmentType.Connector))                             //We've found a terminal connector

                        {
#if OVERLOAD_LEVEL_EDITOR
                            level.editor.AddOutputText("Spitting chunk " + chunknum + "( " + m_chunk_size[chunknum] + " segments)");
#endif
                            int exit_side = FindExitSide(seg, other_segnum);

                            //Compute size of new chunk(s)
                            int num_sub_chunks = (m_chunk_size[chunknum] + MAX_CONNECTOR_CHUNK_SIZE - 1) / MAX_CONNECTOR_CHUNK_SIZE;
                            int new_chunk_size = (m_chunk_size[chunknum] + num_sub_chunks / 2) / num_sub_chunks;

                            //The first batch of segments stay in the old chunk
                            for (int t = new_chunk_size; t > 0; t--)
                            {
                                exit_side = FindExitSide(seg, other_segnum);
                                if (exit_side != -1)
                                {
                                    other_segnum = segnum;
                                    segnum       = seg.neighbor[exit_side];
                                    seg          = level.segment[segnum];
                                }
                            }

                            //Walk through chain until halfway, moving segments to new chunk
                            int new_chunk_num = m_num_chunks++;
                            int moved_count   = 0;

                            while ((exit_side != -1) && ((SegmentTypes[segnum] == SegmentType.Connector) || (SegmentTypes[segnum] == SegmentType.Single)))
                            {
                                seg.m_chunk_num = new_chunk_num;
                                m_chunk_size[chunknum]--;
                                m_chunk_size[new_chunk_num]++;
                                moved_count++;
                                exit_side = FindExitSide(seg, other_segnum);
                                if (exit_side != -1)
                                {
                                    other_segnum = segnum;
                                    segnum       = seg.neighbor[exit_side];
                                    seg          = level.segment[segnum];
                                }
                                if (moved_count == new_chunk_size)
                                {
                                    new_chunk_num = m_num_chunks++;
                                    moved_count   = 0;
                                }
                            }
                        }
                    }
                }
            }             // if EnableAutomaticChunking

            //Get all the manually-added separation planes
            List <SplitPlane> planes = new List <SplitPlane>();
            foreach (int segnum in level.EnumerateAliveSegmentIndices())
            {
                Segment seg = level.segment[segnum];

                for (int sidenum = 0; sidenum < 6; sidenum++)
                {
                    Side side = seg.side[sidenum];
                    if (side.chunk_plane_order != -1)
                    {
                        planes.Add(new SplitPlane(segnum, sidenum, side.chunk_plane_order));
                    }
                }
            }

            //If we have any planes, sort them and do the splits
            if (planes.Count > 0)
            {
                //Sort planes
                planes.Sort((p1, p2) => p1.m_order.CompareTo(p2.m_order));

                //Process the planes in order
                foreach (SplitPlane plane in planes)
                {
                    Segment seg  = level.segment[plane.m_segnum];
                    Side    side = seg.side[plane.m_sidenum];

                    int connected_segnum = seg.neighbor[plane.m_sidenum];

                    //Ok, found one.  Split the chunk this segment is in.
                    int            old_chunk_num = seg.m_chunk_num;
                    int            new_chunk_num = m_num_chunks++;
                    OpenTK.Vector3 sep_normal    = side.FindNormal();
                    OpenTK.Vector3 sep_vert      = level.vertex[side.vert[0]].position;

                    foreach (int checksegnum in level.EnumerateAliveSegmentIndices())
                    {
                        Segment checkseg = level.segment[checksegnum];
                        if (checkseg.m_chunk_num != old_chunk_num)
                        {
                            continue;
                        }

                        if (OpenTK.Vector3.Dot(checkseg.FindCenter() - sep_vert, sep_normal) < 0.0f)
                        {
                            checkseg.m_chunk_num = new_chunk_num;
                            m_chunk_size[old_chunk_num]--;
                            m_chunk_size[new_chunk_num]++;
                        }
                    }

                    //Check to see if either of resulting chunks contain non-connected geometry, and if so add them back to the proper chunk
                    if (connected_segnum != -1)
                    {
                        RejoinDisconnectedChunks(plane.m_segnum, new_chunk_num);
                        RejoinDisconnectedChunks(connected_segnum, old_chunk_num);
                    }
                }
            }

            // Compact the chunks array
            int[] map_old_chunk_to_compact_chunk = new int[m_num_chunks];
            int   compact_chunk_count            = 0;
            for (int chunknum = 0; chunknum < m_num_chunks; ++chunknum)
            {
                if (m_chunk_size[chunknum] == 0)
                {
                    map_old_chunk_to_compact_chunk[chunknum] = -1;
                }
                else
                {
                    map_old_chunk_to_compact_chunk[chunknum] = compact_chunk_count++;
                }
            }

            foreach (int segnum in level.EnumerateAliveSegmentIndices())
            {
                Segment seg = level.segment[segnum];
                System.Diagnostics.Debug.Assert(seg.m_chunk_num >= 0 && seg.m_chunk_num < m_num_chunks);

                int compact_chunk_idx = map_old_chunk_to_compact_chunk[seg.m_chunk_num];
                System.Diagnostics.Debug.Assert(compact_chunk_idx != -1);

                seg.m_chunk_num = compact_chunk_idx;
            }

            level.m_num_chunks = compact_chunk_count;

#if OVERLOAD_LEVEL_EDITOR
            level.editor.AddOutputText("Num segments = " + num_segments + ", num chunks = " + level.m_num_chunks);

            //Generate colors for chunks
            for (int c = 0; c < m_num_chunks; c++)
            {
                level.ChunkColor[c] = System.Drawing.Color.FromArgb(255, Utility.RandomRange(0, 127), Utility.RandomRange(0, 127), Utility.RandomRange(0, 127));
            }
#endif  //OVERLOAD_LEVEL_EDITOR
        }