Ejemplo n.º 1
0
    /// <summary>
    /// Update this chunk's voxels
    /// </summary>
    public void UpdateChunk(uint Tick)
    {
        byte          tickNumber = (byte)Tick;
        List <Notify> Changes    = new List <Notify>();

        // Update voxels
        for (int x = 0; x < ChunkWidth; ++x)
        {
            for (int y = 0; y < ChunkHeight; ++y)
            {
                for (int z = 0; z < ChunkWidth; ++z)
                {
                    // Abort early, as this chunk has gone out of usage
                    if (!bInUse)
                    {
                        return;
                    }

                    // Ignore
                    VoxelInstance voxel = Get(x, y, z);
                    if (voxel == null || voxel.mBehaviour == null)
                    {
                        continue;
                    }

                    // Check if this hasn't already been altered this tick (Maybe by another behaviour)
                    if (voxel.mTickNumber == tickNumber)
                    {
                        continue;
                    }
                    else
                    {
                        voxel.mTickNumber = tickNumber;
                    }


                    ushort wasID = voxel.mID;

                    // Notify if there was a change
                    if (voxel.mBehaviour.UpdateVoxel(Tick, new Point(x, y, z), voxel, this))
                    {
                        Changes.Add(new Notify(new Point(x, y, z), wasID, voxel.mID));
                    }
                }
            }
        }

        if (Changes.Count != 0)
        {
            QueueJob(new Job_QueueNotifies(this, Changes), 10);
        }
    }
Ejemplo n.º 2
0
    /// <summary>
    /// Attempt to place a voxel, and then create the required notfies
    /// </summary>
    /// <param name="OverwriteTypeMask">Bit mask to determine what voxel types are allowed to be overwritten</param>
    /// <returns>If successful</returns>
    public bool PlaceVoxel(int x, int y, int z, ushort ID, ushort MetaFlags = ushort.MaxValue, int OverwriteTypeMask = 1)
    {
        VoxelInstance voxel = GetVoxel(x, y, z);

        // Place if current voxel type is none or is in overwrite task mask
        if (voxel != null && (voxel.mType == VoxelType.None || ((1 << (int)voxel.mType) & OverwriteTypeMask) != 0))
        {
            voxel.SetNew(ID, MetaFlags);
            NotifyVoxelChange(x, y, z, 0, ID);
            return(true);
        }

        return(false);
    }
Ejemplo n.º 3
0
    /// <summary>
    /// Set data for a specific voxel (in local coordinates; will use another chunk if out of bounds)
    /// </summary>
    public VoxelInstance Set(int x, int y, int z, ushort ID, ushort MetaFlags = ushort.MaxValue)
    {
        if (x >= 0 && x < ChunkWidth && y >= 0 && y < ChunkHeight && z >= 0 && z < ChunkWidth)
        {
            VoxelInstance voxel = mVoxelData[x, y, z];
            voxel.SetNew(ID, MetaFlags);
            return(voxel);
        }

        // Try to use another chunk, if out of range
        else
        {
            return(mTerrain.SetVoxel(mChunkID.X * ChunkWidth + x, y, mChunkID.Z * ChunkWidth + z, ID, MetaFlags));
        }
    }
Ejemplo n.º 4
0
    /// <summary>
    /// Attempt to destroy a voxel, and then create the required notfies
    /// </summary>
    /// <returns>If successful</returns>
    public bool DestroyVoxel(int x, int y, int z)
    {
        // Cannot destroy bottom of world
        if (y == 0)
        {
            return(false);
        }

        VoxelInstance voxel = GetVoxel(x, y, z);

        if (voxel != null && voxel.mType != VoxelType.None)
        {
            ushort oldID = voxel.mID;
            voxel.SetNew(0);
            NotifyVoxelChange(x, y, z, oldID, 0);
            return(true);
        }

        return(false);
    }
Ejemplo n.º 5
0
    private void AttemptAirDisperse(VoxelInstance From, VoxelInstance To, bool ForceFill = false)
    {
        if (To == null || From.mMetaFlags == 0 || To.mType != VoxelType.None)
        {
            return;
        }


        // Fill air with liquid
        if (ForceFill)
        {
            To.SetNew(From.mID, From.mMetaFlags);
            From.mMetaFlags = 0;
            To.mTickNumber  = From.mTickNumber;
        }
        else
        {
            To.SetNew(From.mID, 1);
            From.mMetaFlags--;
            To.mTickNumber = From.mTickNumber;
        }
    }
Ejemplo n.º 6
0
    /// <summary>
    /// Attempt to get the voxel the creature is currently embedded in or stood on
    /// </summary>
    /// <param name="IsEmbedded">Is the creature actually inside of a voxel (Non-air)</param>
    /// <returns>If succeeds to get a voxel or not i.e. Is it in voxel space</returns>
    public virtual bool TryGetFloor(out VoxelInstance Voxel, out bool IsEmbedded)
    {
        // Check to see if embedded, if so, return that
        VoxelInstance voxel = mTerrain.GetVoxel(mWorldLocation.x, mWorldLocation.y, mWorldLocation.z);


        // Out of voxel space, so no further check will be correct anyway
        if (voxel == null)
        {
            Voxel      = null;
            IsEmbedded = false;
            return(false);
        }

        // Embedded in voxel
        if (voxel.mType != VoxelType.None)
        {
            Voxel      = voxel;
            IsEmbedded = true;
            return(true);
        }


        // Check voxel below
        voxel = mTerrain.GetVoxel(mWorldLocation.x, mWorldLocation.y - 1, mWorldLocation.z);
        if (voxel != null)
        {
            Voxel      = voxel;
            IsEmbedded = false;
            return(true);
        }

        // Failed (Must be about to fall out of world)
        Voxel      = null;
        IsEmbedded = false;
        return(false);
    }
Ejemplo n.º 7
0
    private void AttemptLiquidDisperse(VoxelInstance From, VoxelInstance To, bool ForceFill = false)
    {
        if (To == null || From.mMetaFlags == 0 || To.mType != VoxelType.Liquid)
        {
            return;
        }

        // Clamp liquid to max height
        if (To.mMetaFlags > VoxelData_Liquid.MaxHeight)
        {
            To.mMetaFlags = (ushort)VoxelData_Liquid.MaxHeight;
        }


        // Same liquid, so fill
        if (From.mID == To.mID)
        {
            if (ForceFill)
            {
                if (To.mMetaFlags != VoxelData_Liquid.MaxHeight)
                {
                    ushort amount = (ushort)(VoxelData_Liquid.MaxHeight - To.mMetaFlags);
                    amount = amount > From.mMetaFlags ? From.mMetaFlags : amount;

                    To.mMetaFlags   += amount;
                    From.mMetaFlags -= amount;
                    To.mTickNumber   = From.mTickNumber;
                }
            }
            else if (To.mMetaFlags < From.mMetaFlags)
            {
                To.mMetaFlags++;
                From.mMetaFlags--;
                To.mTickNumber = From.mTickNumber;
            }
        }
    }
Ejemplo n.º 8
0
    /// <summary>
    /// Attempt to get the voxel the creature is currently embedded in or stood on
    /// </summary>
    /// <returns>If succeeds to get a voxel or not i.e. Is it in voxel space</returns>
    public bool TryGetFloor(out VoxelInstance Voxel)
    {
        bool e;

        return(TryGetFloor(out Voxel, out e));
    }
Ejemplo n.º 9
0
    /// <summary>
    /// Build the mesh data
    /// </summary>
    public override void Execute()
    {
        mMeshData.Clear();


        for (int x = 0; x < VoxelChunk.ChunkWidth; ++x)
        {
            for (int y = 0; y < VoxelChunk.ChunkHeight; ++y)
            {
                for (int z = 0; z < VoxelChunk.ChunkWidth; ++z)
                {
                    if (bIsAborted)
                    {
                        return;
                    }

                    VoxelInstance voxel = mChunk.Get(x, y, z);
                    VoxelInstance check = null;

                    // Ignore if not part of terrain
                    if (voxel.mType != VoxelType.Liquid)
                    {
                        continue;
                    }

                    bool bBuildTop, bBuildLeft, bBuildRight, bBuildFront, bBuildBack;

                    bBuildTop   = ((check = mChunk.Get(x, y + 1, z)) == null || check.mType != VoxelType.Liquid);
                    bBuildLeft  = (check = mChunk.Get(x - 1, y, z)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f));
                    bBuildRight = (check = mChunk.Get(x + 1, y, z)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f));
                    bBuildFront = (check = mChunk.Get(x, y, z - 1)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f));
                    bBuildBack  = (check = mChunk.Get(x, y, z + 1)) != null && (check.mType != VoxelType.Liquid || (!bBuildTop && GetLiquidHeight(check) != 1.0f));

                    // Do height changes for top layer
                    if (bBuildTop)
                    {
                        float mHeight = GetLiquidHeight(voxel);

                        VoxelInstance vForwardLeft   = mChunk.Get(x - 1, y, z - 1);
                        VoxelInstance vForwardCentre = mChunk.Get(x, y, z - 1);
                        VoxelInstance vForwardRight  = mChunk.Get(x + 1, y, z - 1);

                        VoxelInstance vMiddleLeft   = mChunk.Get(x - 1, y, z);
                        VoxelInstance vMiddleCentre = mChunk.Get(x, y, z);
                        VoxelInstance vMiddleRight  = mChunk.Get(x + 1, y, z);

                        VoxelInstance vBackLeft   = mChunk.Get(x - 1, y, z + 1);
                        VoxelInstance vBackCentre = mChunk.Get(x, y, z + 1);
                        VoxelInstance vBackRight  = mChunk.Get(x + 1, y, z + 1);

                        // Work out heights by taking average at corners
                        float forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight;
                        {
                            ushort c = 1;
                            forwardLeftHeight = mHeight;
                            if (vForwardCentre != null && vForwardCentre.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardLeftHeight += GetLiquidHeight(vForwardCentre);
                            }
                            if (vForwardLeft != null && vForwardLeft.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardLeftHeight += GetLiquidHeight(vForwardLeft);
                            }
                            if (vMiddleLeft != null && vMiddleLeft.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardLeftHeight += GetLiquidHeight(vMiddleLeft);
                            }
                            forwardLeftHeight /= (float)c;
                        }
                        {
                            ushort c = 1;
                            forwardRightHeight = mHeight;
                            if (vForwardCentre != null && vForwardCentre.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardRightHeight += GetLiquidHeight(vForwardCentre);
                            }
                            if (vForwardRight != null && vForwardRight.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardRightHeight += GetLiquidHeight(vForwardRight);
                            }
                            if (vMiddleRight != null && vMiddleRight.mType == VoxelType.Liquid)
                            {
                                ++c;
                                forwardRightHeight += GetLiquidHeight(vMiddleRight);
                            }
                            forwardRightHeight /= (float)c;
                        }
                        {
                            ushort c = 1;
                            backLeftHeight = mHeight;
                            if (vBackCentre != null && vBackCentre.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backLeftHeight += GetLiquidHeight(vBackCentre);
                            }
                            if (vBackLeft != null && vBackLeft.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backLeftHeight += GetLiquidHeight(vBackLeft);
                            }
                            if (vMiddleLeft != null && vMiddleLeft.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backLeftHeight += GetLiquidHeight(vMiddleLeft);
                            }
                            backLeftHeight /= (float)c;
                        }
                        {
                            ushort c = 1;
                            backRightHeight = mHeight;
                            if (vBackCentre != null && vBackCentre.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backRightHeight += GetLiquidHeight(vBackCentre);
                            }
                            if (vBackRight != null && vBackRight.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backRightHeight += GetLiquidHeight(vBackRight);
                            }
                            if (vMiddleRight != null && vMiddleRight.mType == VoxelType.Liquid)
                            {
                                ++c;
                                backRightHeight += GetLiquidHeight(vMiddleRight);
                            }
                            backRightHeight /= (float)c;
                        }


                        mMeshData.AddTopPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight);

                        if (bBuildLeft)
                        {
                            mMeshData.AddLeftPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight);
                        }
                        if (bBuildRight)
                        {
                            mMeshData.AddRightPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight);
                        }

                        if (bBuildFront)
                        {
                            mMeshData.AddFrontPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight);
                        }
                        if (bBuildBack)
                        {
                            mMeshData.AddBackPanel(x, y, z, voxel.mMainTileID, forwardLeftHeight, forwardRightHeight, backLeftHeight, backRightHeight);
                        }
                    }
                    else
                    {
                        if (bBuildLeft)
                        {
                            mMeshData.AddLeftPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1);
                        }
                        if (bBuildRight)
                        {
                            mMeshData.AddRightPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1);
                        }

                        if (bBuildFront)
                        {
                            mMeshData.AddFrontPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1);
                        }
                        if (bBuildBack)
                        {
                            mMeshData.AddBackPanel(x, y, z, voxel.mMainTileID, 1, 1, 1, 1);
                        }
                    }
                }
            }
        }

        mMeshData.Cook();
    }
Ejemplo n.º 10
0
 private float GetLiquidHeight(VoxelInstance Voxel)
 {
     return((Voxel.mMetaFlags > VoxelData_Liquid.MaxHeight ? VoxelData_Liquid.MaxHeight : Voxel.mMetaFlags) / (float)VoxelData_Liquid.MaxHeight);
 }
Ejemplo n.º 11
0
    /// <summary>
    /// Update a specific voxel (Called from world update thread)
    /// </summary>
    public override bool UpdateVoxel(uint Tick, Point LocalPosition, VoxelInstance Voxel, VoxelChunk Chunk)
    {
        // Perform cleanup, if liquid too small
        if (Tick % mCleanRate == 0 && mRandom.Next(0, 100) < mCleanPercent)
        {
            // Replace with air, if no fill
            if (Voxel.mMetaFlags <= 1)
            {
                Voxel.SetNew(0);
                return(true);
            }
        }

        // Attempt to settle liquids other than puddles (Put at multiple of 2)
        if (Tick % mSettleRate == 0 && Voxel.mMetaFlags > 1)
        {
            if (Voxel.mMetaFlags % 2 != 0)
            {
                Voxel.mMetaFlags--;
                return(true);
            }
            if (Voxel.mMetaFlags == 0)
            {
                Voxel.SetNew(0);
                return(true);
            }
        }

        // Only update at given tick rate
        if (Tick % mUpdateRate != 0)
        {
            return(false);
        }


        // Clamp liquid to max height
        if (Voxel.mMetaFlags > VoxelData_Liquid.MaxHeight)
        {
            Voxel.mMetaFlags = (ushort)VoxelData_Liquid.MaxHeight;
        }


        ushort startHeight = Voxel.mMetaFlags;

        VoxelInstance above = Chunk.Get(LocalPosition.x, LocalPosition.y + 1, LocalPosition.z);
        VoxelInstance below = Chunk.Get(LocalPosition.x, LocalPosition.y - 1, LocalPosition.z);
        VoxelInstance left  = Chunk.Get(LocalPosition.x - 1, LocalPosition.y, LocalPosition.z);
        VoxelInstance right = Chunk.Get(LocalPosition.x + 1, LocalPosition.y, LocalPosition.z);
        VoxelInstance front = Chunk.Get(LocalPosition.x, LocalPosition.y, LocalPosition.z - 1);
        VoxelInstance back  = Chunk.Get(LocalPosition.x, LocalPosition.y, LocalPosition.z + 1);


        // Move liquid down and then out
        AttemptLiquidDisperse(Voxel, below, true);
        AttemptAirDisperse(Voxel, below, true);

        if (Voxel.mMetaFlags > 1)
        {
            // Shuffle order everytime to prevent any flattening issues
            uint order = (uint)mRandom.Next(0, 4);

            switch (order)
            {
            case 0:
                AttemptAirDisperse(Voxel, left);
                AttemptAirDisperse(Voxel, right);
                AttemptAirDisperse(Voxel, front);
                AttemptAirDisperse(Voxel, back);

                AttemptLiquidDisperse(Voxel, left);
                AttemptLiquidDisperse(Voxel, right);
                AttemptLiquidDisperse(Voxel, front);
                AttemptLiquidDisperse(Voxel, back);
                break;

            case 1:
                AttemptAirDisperse(Voxel, back);
                AttemptAirDisperse(Voxel, left);
                AttemptAirDisperse(Voxel, right);
                AttemptAirDisperse(Voxel, front);

                AttemptLiquidDisperse(Voxel, back);
                AttemptLiquidDisperse(Voxel, left);
                AttemptLiquidDisperse(Voxel, right);
                AttemptLiquidDisperse(Voxel, front);
                break;

            case 2:
                AttemptAirDisperse(Voxel, front);
                AttemptAirDisperse(Voxel, back);
                AttemptAirDisperse(Voxel, left);
                AttemptAirDisperse(Voxel, right);

                AttemptLiquidDisperse(Voxel, front);
                AttemptLiquidDisperse(Voxel, back);
                AttemptLiquidDisperse(Voxel, left);
                AttemptLiquidDisperse(Voxel, right);
                break;

            case 3:
                AttemptAirDisperse(Voxel, right);
                AttemptAirDisperse(Voxel, front);
                AttemptAirDisperse(Voxel, back);
                AttemptAirDisperse(Voxel, left);

                AttemptLiquidDisperse(Voxel, right);
                AttemptLiquidDisperse(Voxel, front);
                AttemptLiquidDisperse(Voxel, back);
                AttemptLiquidDisperse(Voxel, left);
                break;
            }
        }


        // Replace with air, if no fill
        if (Voxel.mMetaFlags == 0)
        {
            Voxel.SetNew(0);
            return(true);
        }

        return(Voxel.mMetaFlags != startHeight);
    }
Ejemplo n.º 12
0
    public void OnRender(List <Vector3> verts, List <int> tris, List <Vector2> uvs, int i, Chunk chunk, VoxelInstance voxel)
    {
        Vector3 corner = voxel.GetPosInChunk().GetVector();

        Rect    textPos = TextureHandler.Instance.GetTexture(texture);
        Vector2 padd    = new Vector2(textPos.width / 100000.0f, textPos.height / 100000.0f);
        Vector2 uvMin   = textPos.min + padd;
        Vector2 uvMax   = textPos.max - padd;

        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.SOUTH))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner, Vector3.up, Vector3.right, uvMin, uvMax, i + verts.Count);
        }
        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.NORTH))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward + Vector3.right, Vector3.up, Vector3.left, uvMin, uvMax, i + verts.Count);
        }
        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.EAST))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.right, Vector3.up, Vector3.forward, uvMin, uvMax, i + verts.Count);
        }
        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.WEST))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward, Vector3.up, Vector3.back, uvMin, uvMax, i + verts.Count);
        }
        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.DOWN))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.forward, Vector3.back, Vector3.right, uvMin, uvMax, i + verts.Count);
        }
        if (chunk.ShouldRender(voxel.GetPosInChunk(), Facing.UP))
        {
            RenderHelper.AddQuad(verts, tris, uvs, corner + Vector3.up, Vector3.forward, Vector3.right, uvMin, uvMax, i + verts.Count);
        }
    }
Ejemplo n.º 13
0
 public float GetMiningDifficulty(VoxelInstance voxel)
 {
     return(miningDifficulty);
 }
Ejemplo n.º 14
0
    /// <summary>
    /// Build the mesh data
    /// </summary>
    public override void Execute()
    {
        mMeshData.Clear();
        byte[] endodedData = new byte[4];


        for (int x = 0; x < VoxelChunk.ChunkWidth; ++x)
        {
            for (int y = 0; y < VoxelChunk.ChunkHeight; ++y)
            {
                for (int z = 0; z < VoxelChunk.ChunkWidth; ++z)
                {
                    if (bIsAborted)
                    {
                        return;
                    }

                    VoxelInstance voxel = mChunk.Get(x, y, z);
                    VoxelInstance check = null;

                    // Ignore if collision disabled
                    if (voxel.bDisableCollision)
                    {
                        continue;
                    }


                    // Check all sides
                    // Up
                    if ((check = mChunk.Get(x, y + 1, z)) == null || check.bDisableCollision)
                    {
                        mMeshData.AddTopPanel(x, y, z, endodedData, true);
                    }
                    // Bottom
                    if ((check = mChunk.Get(x, y - 1, z)) != null && check.bDisableCollision)
                    {
                        mMeshData.AddBottomPanel(x, y, z, endodedData, true);
                    }

                    // Left
                    if ((check = mChunk.Get(x - 1, y, z)) != null && check.bDisableCollision)
                    {
                        mMeshData.AddLeftPanel(x, y, z, endodedData, true);
                    }
                    // Right
                    if ((check = mChunk.Get(x + 1, y, z)) != null && check.bDisableCollision)
                    {
                        mMeshData.AddRightPanel(x, y, z, endodedData, true);
                    }

                    // Back
                    if ((check = mChunk.Get(x, y, z + 1)) != null && check.bDisableCollision)
                    {
                        mMeshData.AddBackPanel(x, y, z, endodedData, true);
                    }
                    // Front
                    if ((check = mChunk.Get(x, y, z - 1)) != null && check.bDisableCollision)
                    {
                        mMeshData.AddFrontPanel(x, y, z, endodedData, true);
                    }
                }
            }
        }

        mMeshData.Cook();
    }
Ejemplo n.º 15
0
    /// <summary>
    /// Perform ray cast against all terrain
    /// </summary>
    /// <param name="R">Ray in unit space</param>
    /// <param name="MaxDistance"></param>
    /// <param name="Hit">Information of the hit, if hit successfully</param>
    /// <param name="IgnoreTransparent">Should voxels with transparent type just be ignoreed in this check</param>
    /// <param name="TypeMask">Bit mask to determine what voxel types to check against</param>
    /// <returns>Does the ray hit</returns>
    public bool PerformRayCast(Ray R, out VoxelHitInfo Hit, float MaxDistance = 32.0f, bool IgnoreTransparent = false, int TypeMask = int.MaxValue)
    {
        Point lastCheck = new Point();
        bool  started   = false;


        for (float i = 0; i < MaxDistance; i += 0.5f)
        {
            Point check = new Point((R.origin + R.direction * i) * WorldManager.UnitToVoxelScale);


            // Don't repeat checks
            if (started && lastCheck == check)
            {
                continue;
            }


            // Ignore invalid height
            if (check.y < 0 || check.y >= VoxelChunk.ChunkHeight)
            {
                // If we were in bounds exit out, as we've left
                if (started)
                {
                    break;
                }
                // Ignore invalid height until we get in bounds
                else
                {
                    continue;
                }
            }
            lastCheck = check;
            started   = true;


            VoxelInstance voxel = GetVoxel(check.x, check.y, check.z);

            // Ignore invalid checks
            if (voxel == null || voxel.mType == VoxelType.None || ((1 << (int)voxel.mType) & TypeMask) == 0 || (IgnoreTransparent && voxel.bIsTransparent))
            {
                continue;
            }


            // Intersect ray against bounding box and see if it hits
            Bounds bounds = new Bounds(new Vector3(check.x, check.y, check.z) * WorldManager.VoxelToUnitScale, new Vector3(1, 1, 1) * WorldManager.VoxelToUnitScale);
            float  d;

            if (bounds.IntersectRay(R, out d))
            {
                Vector3 c      = bounds.ClosestPoint(R.origin + R.direction * (d - 0.0001f));
                Vector3 normal = new Vector3(0, 0, 0);

                // Work out normal based on closest point
                if (c.y == bounds.min.y)
                {
                    normal.y = -1;
                }
                if (c.y == bounds.max.y)
                {
                    normal.y = 1;
                }
                if (c.x == bounds.min.x)
                {
                    normal.x = -1;
                }
                if (c.x == bounds.max.x)
                {
                    normal.x = 1;
                }
                if (c.z == bounds.min.z)
                {
                    normal.z = -1;
                }
                if (c.z == bounds.max.z)
                {
                    normal.z = 1;
                }

                Hit = new VoxelHitInfo(check.x, check.y, check.z, voxel, normal.normalized);
                return(true);
            }
        }

        Hit = new VoxelHitInfo();
        return(false);
    }
Ejemplo n.º 16
0
    /// <summary>
    /// Build the mesh data
    /// </summary>
    public override void Execute()
    {
        mMeshData.Clear();

        // First 2 bits are the tile id
        // Second bit is the tile's exposure (How close is it to air 0-4; 0:Next to air, 4:No air within 3 voxels)
        byte[] endodedData = new byte[4];


        for (int x = 0; x < VoxelChunk.ChunkWidth; ++x)
        {
            for (int y = 0; y < VoxelChunk.ChunkHeight; ++y)
            {
                for (int z = 0; z < VoxelChunk.ChunkWidth; ++z)
                {
                    if (bIsAborted)
                    {
                        return;
                    }

                    VoxelInstance voxel       = mChunk.Get(x, y, z);
                    VoxelInstance check       = null;
                    bool          transparent = voxel.bIsTransparent;

                    // Ignore if not part of terrain
                    if (voxel.mType != VoxelType.Terrain)
                    {
                        continue;
                    }

                    byte[] tileBits;

                    // Use main tile for top tile
                    tileBits       = System.BitConverter.GetBytes(voxel.mMainTileID);
                    endodedData[0] = tileBits[0];
                    endodedData[1] = tileBits[1];
                    endodedData[2] = 0;


                    // Check all sides
                    // Up
                    if ((check = mChunk.Get(x, y + 1, z)) == null || check.mType != VoxelType.Terrain || transparent != check.bIsTransparent)
                    {
                        mMeshData.AddTopPanel(x, y, z, endodedData);
                    }

                    // Include top tile and work out how exposed this tile is (Will be later culled in rendering, if neccessary)
                    else
                    {
                        byte airExposure = 0;

                        // Work out the air exposure for this exposure voxel
                        if ((check = mChunk.Get(x, y + 1, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent)
                        {
                            airExposure = 0;
                        }
                        else if ((check = mChunk.Get(x, y + 2, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent)
                        {
                            airExposure = 1;
                        }
                        else if ((check = mChunk.Get(x, y + 3, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent)
                        {
                            airExposure = 2;
                        }
                        else if ((check = mChunk.Get(x, y + 4, z)) == null || check.mType == VoxelType.None || transparent != check.bIsTransparent)
                        {
                            airExposure = 3;
                        }
                        else
                        {
                            airExposure = 4;
                        }

                        // Check adjacent tiles
                        if (airExposure == 4)
                        {
                            for (byte c = 1; c <= 3; ++c)
                            {
                                if ((check = mChunk.Get(x + c, y, z)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent))
                                {
                                    airExposure = c;
                                    break;
                                }
                                if ((check = mChunk.Get(x - c, y, z)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent))
                                {
                                    airExposure = c;
                                    break;
                                }
                                if ((check = mChunk.Get(x, y, z + c)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent))
                                {
                                    airExposure = c;
                                    break;
                                }
                                if ((check = mChunk.Get(x, y, z - c)) != null && (check.mType == VoxelType.None || transparent != check.bIsTransparent))
                                {
                                    airExposure = c;
                                    break;
                                }
                            }
                        }

                        endodedData[2] = airExposure;
                        mMeshData.AddTopPanel(x, y, z, endodedData);
                    }


                    // Switch to secondary tile
                    tileBits       = System.BitConverter.GetBytes(voxel.mSecondaryTileID);
                    endodedData[0] = tileBits[0];
                    endodedData[1] = tileBits[1];
                    endodedData[2] = 0;


                    // Left
                    if ((check = mChunk.Get(x - 1, y, z)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent))
                    {
                        mMeshData.AddLeftPanel(x, y, z, endodedData);
                    }
                    // Right
                    if ((check = mChunk.Get(x + 1, y, z)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent))
                    {
                        mMeshData.AddRightPanel(x, y, z, endodedData);
                    }

                    // Back
                    if ((check = mChunk.Get(x, y, z + 1)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent))
                    {
                        mMeshData.AddBackPanel(x, y, z, endodedData);
                    }
                    // Front
                    if ((check = mChunk.Get(x, y, z - 1)) != null && (check.mType != VoxelType.Terrain || transparent != check.bIsTransparent))
                    {
                        mMeshData.AddFrontPanel(x, y, z, endodedData);
                    }
                }
            }
        }

        mMeshData.Cook();
    }