コード例 #1
0
    public Item SpawnItem(Type itemType, Vector3 position, Quaternion rotation, string model)
    {
        if (typeof(Item).IsAssignableFrom(itemType))           // Is an item, spawn that shit
        {
            GameObject go = (GameObject)GameObject.Instantiate(GameController.Instance.VoxPrefab, position, rotation);

            Item item = (Item)go.AddComponent(itemType);

            item.gameObject.name = item.Name;

            string useModel = (ModelRegister.ContainsKey(model) ? model : (ModelRegister.ContainsKey(item.DefaultModel) ? item.DefaultModel : "Default"));
            using (BinaryReader reader = new BinaryReader(new MemoryStream(ModelRegister[useModel]))) {
                VoxelUtil.FromMagica(reader, go.GetComponentInChildren <Volume>().gameObject, 0.075f, false);
            }

            Volume vol = item.GetComponentInChildren <Volume>();
            vol.Pivot = (new Vector3(vol.XSize, vol.YSize, vol.ZSize) * vol.VoxelSize) / 2f;
            vol.UpdatePivot();

            GameController.InvokeSpawned(this, item);

            return(item);
        }

        return(null);
    }
コード例 #2
0
    public Pawn SpawnPawn(Type pawnType, Vector3 position, Quaternion rotation, string model)
    {
        if (typeof(PlayerController).IsAssignableFrom(pawnType))
        {
            Log("cannot spawn PlayerController via SpawnPawn; use SpawnPlayer instead.", DebugWarningLevel.ERROR);
        }
        else if (typeof(Pawn).IsAssignableFrom(pawnType))           // Is a non-player pawn, spawn that shit
        {
            GameObject go   = (GameObject)GameObject.Instantiate(GameController.Instance.VoxPrefab, position, rotation);
            Pawn       pawn = (Pawn)go.AddComponent(pawnType);

            pawn.gameObject.name = pawn.Name;

            string useModel = (ModelRegister.ContainsKey(model) ? model : (ModelRegister.ContainsKey(pawn.DefaultModel) ? pawn.DefaultModel : "Default"));
            using (BinaryReader reader = new BinaryReader(new MemoryStream(ModelRegister[useModel]))) {
                VoxelUtil.FromMagica(reader, go.GetComponentInChildren <Volume>().gameObject, 0.075f, false);
            }

            Volume vol = pawn.GetComponentInChildren <Volume>();
            vol.Pivot = (new Vector3(vol.XSize, vol.YSize, vol.ZSize) * vol.VoxelSize) / 2f;
            vol.UpdatePivot();

            GameController.InvokeSpawned(this, pawn);

            return(pawn);
        }

        return(null);
    }
コード例 #3
0
        public void Execute(int index)
        {
            int3 gridPosition  = VoxelUtil.To3DIndex(index, chunkSize);
            int3 worldPosition = gridPosition + chunkPosition * chunkSize;

            RandomVoxel(out Voxel voxel, worldPosition);
            voxels[index] = voxel;
        }
コード例 #4
0
    IEnumerator UpdateMesh()
    {
        if (Updating)
        {
            yield break;
        }

        if (!generator.CanUpdate)
        {
            yield break;
        }

        generator.UpdatingChunks++;

        int3 chunkSizeInt3 = VoxelUtil.ToInt3(chunkSize);

        List <Voxel[]> neighborVoxels = generator.GetNeighborVoxels(chunkPosition, 1);

        lightData?.Dispose();
        lightData = new VoxelLightBuilder.NativeLightData(chunkSizeInt3);
        yield return(lightData.ScheduleLightingJob(neighborVoxels, VoxelUtil.ToInt3(chunkPosition), chunkSizeInt3, 1, argent));

        meshData?.Dispose();
        meshData = new VoxelMeshBuilder.NativeMeshData(VoxelUtil.ToInt3(chunkSize));
        yield return(meshData.ScheduleMeshingJob(voxels, lightData, VoxelUtil.ToInt3(chunkSize), generator.SimplifyingMethod, argent));

        meshData.GetMeshInformation(out int verticeSize, out int indicesSize);

        if (verticeSize > 0 && indicesSize > 0)
        {
            mesh.Clear();
            mesh.SetVertices(meshData.nativeVertices, 0, verticeSize);
            mesh.SetNormals(meshData.nativeNormals, 0, verticeSize);
            mesh.SetColors(meshData.nativeColors, 0, verticeSize);
            mesh.SetUVs(0, meshData.nativeUVs, 0, verticeSize);
            mesh.SetIndices(meshData.nativeIndices, 0, indicesSize, MeshTopology.Triangles, 0);

            mesh.RecalculateNormals();
            mesh.RecalculateBounds();

            if (argent)
            {
                SetSharedMesh(mesh);
            }
            else
            {
                VoxelColliderBuilder.Instance.Enqueue(this, mesh);
            }
        }

        lightData.Dispose();
        meshData.Dispose();
        dirty            = false;
        argent           = false;
        gameObject.layer = LayerMask.NameToLayer("Voxel");
        meshUpdator      = null;
        generator.UpdatingChunks--;
    }
コード例 #5
0
    void GenerateChunkByTargetPosition()
    {
        if (target == null)
        {
            return;
        }

        Vector3Int targetPosition = VoxelUtil.WorldToChunk(target.position, chunkSize);

        if (lastTargetChunkPosition == targetPosition)
        {
            return;
        }

        foreach (ChunkNode chunkNode in generateChunkQueue)
        {
            Vector3Int deltaPosition = targetPosition - chunkNode.chunkPosition;
            if (chunkSpawnSize.x < Mathf.Abs(deltaPosition.x) || chunkSpawnSize.y < Mathf.Abs(deltaPosition.y) || chunkSpawnSize.z < Mathf.Abs(deltaPosition.z))
            {
                generateChunkQueue.Remove(chunkNode);
                continue;
            }

            generateChunkQueue.UpdatePriority(chunkNode, (targetPosition - chunkNode.chunkPosition).sqrMagnitude);
        }

        for (int x = targetPosition.x - chunkSpawnSize.x; x <= targetPosition.x + chunkSpawnSize.x; x++)
        {
            for (int y = targetPosition.y - chunkSpawnSize.y; y <= targetPosition.y + chunkSpawnSize.y; y++)
            {
                for (int z = targetPosition.z - chunkSpawnSize.z; z <= targetPosition.z + chunkSpawnSize.z; z++)
                {
                    Vector3Int chunkPosition = new Vector3Int(x, y, z);
                    if (chunks.ContainsKey(chunkPosition))
                    {
                        continue;
                    }

                    ChunkNode newNode = new ChunkNode {
                        chunkPosition = chunkPosition
                    };

                    if (generateChunkQueue.Contains(newNode))
                    {
                        continue;
                    }

                    generateChunkQueue.Enqueue(newNode, (targetPosition - chunkPosition).sqrMagnitude);
                }
            }
        }

        lastTargetChunkPosition = targetPosition;
    }
コード例 #6
0
        public void Set(float x, float y, float z, T data)
        {
            int xx = (int)x;
            int yy = (int)y;
            int zz = (int)z;

            Vector3i       loc       = new Vector3i(xx >> regionBits, yy >> regionBits, zz >> regionBits);
            RegionData <T> DataCache = GetOrCreateRegion(loc);

            DataCache.Set(VoxelUtil.WorldToChunkCoord(x), VoxelUtil.WorldToChunkCoord(y), VoxelUtil.WorldToChunkCoord(z), data);
        }
コード例 #7
0
    IEnumerator InitUpdator()
    {
        int numVoxels = chunkSize.x * chunkSize.y * chunkSize.z;

        voxels    = new Voxel[numVoxels];
        voxelData = new NoiseGenerator.NativeVoxelData(VoxelUtil.ToInt3(chunkSize));
        yield return(voxelData.Generate(voxels, VoxelUtil.ToInt3(chunkPosition), VoxelUtil.ToInt3(chunkSize)));

        dirty       = true;
        initialized = true;
    }
コード例 #8
0
        public WorldFile(int LOD, int ChunkIDX, int ChunkIDY, int X, int Y, float Scale)
        {
            LODID = LOD;
            IDX   = ChunkIDX;
            IDY   = ChunkIDY;

            WSX = X;
            WSY = Y;

            SX = (int)Math.Round(X / Scale);
            SY = (int)Math.Round(Y / Scale);

            TerrainScale = Scale;

            HeightMap   = new int[SX + 1, SY + 1];
            MaterialMap = new byte[SX * MaterialDensity, SY *MaterialDensity];

            SecondaryMaterialMap = new byte[SX * MaterialDensity, SY *MaterialDensity];
            BlendAlphaMap        = new byte[SX * MaterialDensity, SY *MaterialDensity];
            DecalMaterialMap     = new byte[SX * MaterialDensity, SY *MaterialDensity];
            DecalAlphaMap        = new byte[SX * MaterialDensity, SY *MaterialDensity];

            WaterHeightMap = new int[SX + 1, SY + 1];
            WaveLengthMap  = new byte[SX + 1, SY + 1];
            WaveHeightMap  = new byte[SX + 1, SY + 1];

            FlowXMap          = new byte[SX, SY];
            FlowYMap          = new byte[SX, SY];
            FlowBackTimeMap   = new byte[SX, SY];
            FlowPulseSpeedMap = new byte[SX, SY];

            WaterMap = new byte[SX, SY];

            FoamRampMap0         = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];
            WaterColorFalloffMap = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];

            WaterColorR = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];
            WaterColorG = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];
            WaterColorB = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];
            WaterColorA = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];

            WaterNormalMap  = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];
            WaterFresnelMap = new byte[SX * WaterColorDensity + 1, SY *WaterColorDensity + 1];

            CoverHeight = new byte[SX * DisplacementDensity + 1, SY *DisplacementDensity + 1];

            VoxelUtil.ReplaceValue(FlowXMap, 0, 128);
            VoxelUtil.ReplaceValue(FlowYMap, 0, 128);

            FileName = ChunkIDX + "-" + ChunkIDY + "-" + LODID;
        }
コード例 #9
0
    public IEnumerator Init(Vector3Int position, TerrainGenerator parent)
    {
        chunkPosition = position;
        generator     = parent;

        meshRenderer.material = generator.ChunkMaterial;

        voxels         = new NativeArray <Voxel>(generator.ChunkSize * generator.ChunkSize * generator.ChunkSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
        noiseJobHandle = NoiseGenerator.Generate(voxels, VoxelUtil.ToInt3(chunkPosition), generator.ChunkSize);
        yield return(new WaitUntil(() => noiseJobHandle.IsCompleted));

        noiseJobHandle.Complete();
        dirty = true;
    }
コード例 #10
0
 // a raycast which returns the index of the hit voxel and the gameobject of the hit chunk
 public BlockInfo MasterRaycast(RaycastHit hit, Vector3 origin, Vector3 direction, float range, bool ignoreTransparent)
 {
     if (raycastHasVoxel(hit))
     { // check if we're actually hitting a chunk
         GameObject hitObject = hit.collider.gameObject;
         swapMesh(hitObject);
         Index hitIndex = hitObject.GetComponent <Chunk>().PositionToVoxelIndex(hit.point, hit.normal, false);
         if (ignoreTransparent)
         { // punch through transparent voxels by raycasting again when a transparent voxel is hit
             reCast(hitIndex, hitObject, hit, range);
         }
         return(VoxelUtil.getVoxelInfo(hit, hitObject));
     }
     return(null);
 }
コード例 #11
0
    public bool GetVoxel(Vector3Int gridPosition, out Voxel voxel)
    {
        if (!initialized)
        {
            voxel = Voxel.Empty;
            return(false);
        }

        if (!VoxelUtil.BoundaryCheck(gridPosition, chunkSize))
        {
            voxel = Voxel.Empty;
            return(false);
        }

        voxel = voxels[VoxelUtil.To1DIndex(gridPosition, chunkSize)];
        return(true);
    }
コード例 #12
0
    public bool SetVoxel(Vector3Int gridPosition, Voxel.VoxelType type)
    {
        if (!initialized)
        {
            return(false);
        }

        if (!VoxelUtil.BoundaryCheck(gridPosition, chunkSize))
        {
            return(false);
        }

        voxels[VoxelUtil.To1DIndex(gridPosition, chunkSize)].data = type;
        dirty  = true;
        argent = true;
        return(true);
    }
コード例 #13
0
        public T Sample(float x, float y, float z, int level = 0)
        {
            int xx = (int)x;
            int yy = (int)y;
            int zz = (int)z;

            RegionData <T> DataCache = null;

            regionStore.TryGetValue(new Vector3i(xx >> regionBits, yy >> regionBits, zz >> regionBits), out DataCache);
            if (DataCache != null)
            {
                return(DataCache.Sample(VoxelUtil.WorldToChunkCoord(x), VoxelUtil.WorldToChunkCoord(y), VoxelUtil.WorldToChunkCoord(z), level));
            }
            else
            {
                return(default(T));
            }
        }
コード例 #14
0
    Chunk GenerateChunk(Vector3Int chunkPosition)
    {
        if (chunks.ContainsKey(chunkPosition))
        {
            return(chunks[chunkPosition]);
        }

        GameObject chunkGameObject = new GameObject(chunkPosition.ToString());

        chunkGameObject.transform.SetParent(transform);
        chunkGameObject.transform.position = VoxelUtil.ChunkToWorld(chunkPosition, chunkSize);

        Chunk newChunk = chunkGameObject.AddComponent <Chunk>();

        StartCoroutine(newChunk.Init(chunkPosition, this));

        chunks.Add(chunkPosition, newChunk);
        return(newChunk);
    }
コード例 #15
0
 public BlockInfo getVoxelInfo(RaycastHit hit, float range, bool ignoreTransparent)
 {
     if (raycastHasVoxel(hit))
     {
         // check if we're actually hitting a chunk
         GameObject hitObject = hit.collider.gameObject;
         if (hitObject.GetComponent <ChunkExtension>() != null)
         {                                                      // if we hit a mesh container instead of a chunk
             hitObject = hitObject.transform.parent.gameObject; // swap the mesh container for the actual chunk object
         }
         Index hitIndex = hitObject.GetComponent <Chunk>().PositionToVoxelIndex(hit.point, hit.normal, false);
         if (ignoreTransparent)
         {
             reCast(hitIndex, hitObject, hit, range);
         }
         return(VoxelUtil.getVoxelInfo(hit, hitObject));
     }
     return(null);
 }
コード例 #16
0
    public Pawn SpawnPlayer(Vector3 position, Quaternion rotation, string model)
    {
        PlayerController pc = GameController.FindObjectOfType <PlayerController>();


        if (pc == null)
        {
            // Instantiate the player

            GameObject go = (GameObject)GameObject.Instantiate(GameController.Instance.PlayerPrefab, position, rotation);
            pc = go.GetComponent <PlayerController>();

            pc.gameObject.name = pc.Name;
        }

        // Setup player model
        string useModel = (ModelRegister.ContainsKey(model) ? model : (ModelRegister.ContainsKey(pc.DefaultModel) ? pc.DefaultModel : "Default"));

        using (BinaryReader reader = new BinaryReader(new MemoryStream(ModelRegister[useModel]))) {
            VoxelUtil.FromMagica(reader, pc.GetComponentInChildren <Volume>().gameObject, 0.075f, false);

            Volume vol = pc.GetComponentInChildren <Volume>();
            vol.Pivot = (new Vector3(vol.XSize, vol.YSize, vol.ZSize) * vol.VoxelSize) / 2f;
            vol.UpdatePivot();
        }

        if (pc.HasStarted)
        {
            pc.Spawn(position);
        }
        else
        {
            pc.QueuedSpawn  = position;
            pc.SpawnAtQueue = true;
        }

        return(pc);
    }
コード例 #17
0
        public void Update(RenderManager Render, Vector3 Position, Vector3 ViewDirection, float Time)
        {
            int[]   LOD          = WorldSettings.LOD;
            Vector3 FilePosition = WorldFile.GetPosition();
            float   Distance     = Math.Min(Math.Abs(Position.X - FilePosition.X), Math.Abs(Position.Y - FilePosition.Y));

            //TODO
            if (WaterData0.Width != WorldFile.WaterMap.GetLength(0) || WaterData0.Height != WorldFile.WaterMap.GetLength(1))
            {
                WaterData0.Dispose();
                WaterData1.Dispose();
                WaterColorData0.Dispose();
                WaterColorData1.Dispose();

                WaterData0 = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.FlowXMap, WorldFile.FlowYMap, WorldFile.FlowPulseSpeedMap, WorldFile.FlowBackTimeMap);
                WaterData1 = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.WaterMap);

                WaterColorData0 = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.WaterColorR, WorldFile.WaterColorG, WorldFile.WaterColorB, WorldFile.WaterColorA);
                WaterColorData1 = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.WaterNormalMap, WorldFile.WaterFresnelMap, WorldFile.FoamRampMap0, WorldFile.WaterColorFalloffMap);
                WaveData0       = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.WaveLengthMap, WorldFile.WaveHeightMap, WorldFile.WaveHeightMap, WorldFile.WaveLengthMap);
            }

            if (WorldFile.HasTerrainUpdate)
            {
                Geom.Shader.Parameters["TerrainScale"].SetValue(WorldFile.TerrainScale);
                Geom.Shader.Parameters["HeightScale"].SetValue(WorldFile.HeightScale);

                Geom.Shader.Parameters["TerrainWidth"].SetValue(WorldFile.SX);
                Geom.Shader.Parameters["TerrainLength"].SetValue(WorldFile.SY);

                Geom.Shader.Parameters["DataWidth"].SetValue(WorldFile.FlowXMap.GetLength(0));
                Geom.Shader.Parameters["DataHeight"].SetValue(WorldFile.FlowXMap.GetLength(1));

                GraphicsUtil.FillTexture(WaterData0, WorldFile.FlowXMap, WorldFile.FlowYMap, WorldFile.FlowPulseSpeedMap, WorldFile.FlowBackTimeMap);
                GraphicsUtil.FillTexture(WaterData1, WorldFile.WaterMap);
                GraphicsUtil.FillTexture(WaterColorData0, WorldFile.WaterColorR, WorldFile.WaterColorG, WorldFile.WaterColorB, WorldFile.WaterColorA);
                GraphicsUtil.FillTexture(WaterColorData1, WorldFile.WaterNormalMap, WorldFile.WaterFresnelMap, WorldFile.FoamRampMap0, WorldFile.WaterColorFalloffMap);
                GraphicsUtil.FillTexture(WaveData0, WorldFile.WaveLengthMap, WorldFile.WaveHeightMap, WorldFile.FoamRampMap0, WorldFile.WaterColorFalloffMap);

                Geom.Shader.Parameters["WaterDataMap0"].SetValue(WaterData0);
                Geom.Shader.Parameters["WaterDataMap1"].SetValue(WaterData1);
                Geom.Shader.Parameters["ColorDataMap0"].SetValue(WaterColorData0);
                Geom.Shader.Parameters["ColorDataMap1"].SetValue(WaterColorData1);
                Geom.Shader.Parameters["WaveDataMap0"].SetValue(WaveData0);

                Geom.Shader.Parameters["HeightMap"].SetValue(Terrain.HeightMap);

                WaterHeightMap.Dispose();
                WaterHeightMap = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, WorldFile.WaterHeightMap);

                //GraphicsUtil.FillTexture(WaterHeightMap, WorldFile.WaterHeightMap);

                Geom.Shader.Parameters["WaterHeightMap"].SetValue(WaterHeightMap);

                WaterClipMap.Dispose();
                WaterClipMap = GraphicsUtil.MaterialMapsToTexture(Render.Graphics, VoxelUtil.AddValues(WorldFile.HeightMap, WorldFile.WaterHeightMap));

                ReflectionRenderTarget.SetClipPlaneMap(Name, WaterClipMap);
                RefractionRenderTarget.SetClipPlaneMap(Name, WaterClipMap);
                DepthMapRenderTarget.SetClipPlaneMap(Name, WaterClipMap);
            }

            Geom.Shader.Parameters["ShineDamper"].SetValue(WorldSettings.WaterShineDamper);
            Geom.Shader.Parameters["Reflectivity"].SetValue(WorldSettings.WaterReflectivity);
            Geom.Shader.Parameters["MinSpecular"].SetValue(WorldSettings.MinimumSpecular);

            Geom.Shader.Parameters["WaterRepeatTime"].SetValue(WorldSettings.WaterRepeatTime);
            Geom.Shader.Parameters["WaterSpeed"].SetValue(WorldSettings.WaterSpeed);

            Geom.PassSetting    = WorldSettings.WaterPassSetting;
            Geom.PassMipSetting = WorldSettings.WaterPassMipSetting;

            Geom.Shader.Parameters["TexSize"].SetValue(WorldSettings.TextureSize);
            Vector3 ChunkPosition = new Vector3(WorldFile.IDX * WorldFile.SX * WorldFile.TerrainScale, WorldFile.IDY * WorldFile.SX * WorldFile.TerrainScale, 0);

            Geom.Shader.Parameters["Position"].SetValue(ChunkPosition);

            Geom.Position = WorldFile.GetPosition();
        }
コード例 #18
0
        public static void GeneratePatternImage(int [,] Voxels, float ScaleX, float ScaleY, LockBitMap PatternImage, LockBitMap TextureLookup)
        {
            float VoxelSizeX = PatternImage.Width / (Voxels.GetLength(0));
            float VoxelSizeY = PatternImage.Height / (Voxels.GetLength(1));

            int ISX = TextureLookup.Width / 16;
            int ISY = TextureLookup.Height / 16;

            Vector2[] Position = new Vector2[]
            {
                new Vector2(0, 0),
                new Vector2(VoxelSizeX, 0),
                new Vector2(0, VoxelSizeY),
                new Vector2(VoxelSizeX, VoxelSizeY),
                new Vector2(VoxelSizeX / 2, 0),
                new Vector2(0, VoxelSizeY / 2),
                new Vector2(VoxelSizeX, VoxelSizeY / 2),
                new Vector2(VoxelSizeX / 2, VoxelSizeY),
                new Vector2(VoxelSizeX / 2, VoxelSizeY / 2)
            };

            PatternImage.Clear();

            List <int[, ]> SplitVoxelFields = VoxelUtil.SplitVoxels(Voxels, 239);

            Vector2 Scale = new Vector2(1.0f / VoxelSizeX, 1.0f / VoxelSizeY);

            for (int index = 0; index < SplitVoxelFields.Count; index++)
            {
                int[,] VoxelField = SplitVoxelFields[index];

                for (int i = 0; i < VoxelField.GetLength(0) - 1; i++)
                {
                    for (int j = 0; j < VoxelField.GetLength(1) - 1; j++)
                    {
                        int Val = 0;
                        Val += VoxelField[i, j] != 0 ? 1 : 0;
                        Val += VoxelField[i + 1, j] != 0 ? 2 : 0;
                        Val += VoxelField[i, j + 1] != 0 ? 4 : 0;
                        Val += VoxelField[i + 1, j + 1] != 0 ? 8 : 0;

                        //int Material = MathUtil.CalculateMost(new int[] { VoxelField[i, j], VoxelField[i + 1, j], VoxelField[i, j + 1], VoxelField[i + 1, j + 1] });

                        Vector2 VoxelPosition = new Vector2(i * VoxelSizeX, j * VoxelSizeY);


                        for (int k = 0; k < MarchingSquaresIndices[Val].Length; k += 3)
                        {
                            Vector2 P1 = Position[MarchingSquaresIndices[Val][k]] + VoxelPosition;
                            Vector2 P2 = Position[MarchingSquaresIndices[Val][k + 1]] + VoxelPosition;
                            Vector2 P3 = Position[MarchingSquaresIndices[Val][k + 2]] + VoxelPosition;

                            int Material = VoxelUtil.GetClosestMaterialVertex(P1, P2, P3, Scale, VoxelField);

                            int MX = (Material / 16);
                            int MY = (Material % 16);

                            FillTriangle(VoxelSizeX, VoxelSizeY, ISX, ISY, MX, MY, ScaleX, ScaleY, P1, P2, P3, PatternImage, TextureLookup);
                        }
                    }
                }
            }
        }