Exemple #1
0
        public Tile(TileDescriptor descriptor)
        {
            _descriptor = descriptor;

            if (descriptor.SpriteInfo != null)
            {
                _collisionArea = new Rect(descriptor.SpriteInfo.Transform.Position.X, descriptor.SpriteInfo.Transform.Position.Y, Settings.TileSize, Settings.TileSize);
            }
            else
            {
                _collisionArea = new Rect(descriptor.Position.X, descriptor.Position.Y, Settings.TileSize, Settings.TileSize);
            }

            _heartbeatListener = new NPCHeartbeatListener();
        }
        public void AddTile(TileDescriptor tile, Stream data)
        {
            string filepath = GetFilePath(tile);
            string dir      = Path.GetDirectoryName(filepath);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }

            var file = File.Create(filepath);

            data.CopyTo(file);
            file.Close();
        }
Exemple #3
0
        public void AddTile(TileDescriptor tile, Stream data)
        {
            MemoryStream memStr = new MemoryStream();

            data.CopyTo(memStr);

            if (_cache[_subCache].ContainsKey(tile))
            {
                _cache[_subCache][tile].Dispose();
                _cache[_subCache][tile] = memStr;
            }
            else
            {
                _cache[_subCache].Add(tile, memStr);
            }
        }
Exemple #4
0
        public Stream GetTile(TileDescriptor tile)
        {
            MemoryStream memStr = new MemoryStream();

            if (!HasTile(tile))
            {
                return(null);
            }
            else
            {
                _cache[_subCache][tile].Position = 0;
                _cache[_subCache][tile].CopyTo(memStr);
            }

            return(memStr);
        }
Exemple #5
0
        /// <summary>
        /// Deal with collisions between an object and a level (based on Lab 2)
        /// </summary>
        /// <param name="currentLevel"></param>
        /// <param name="obj"></param>
        private void UpdateObjectLevelCollisions(Level currentLevel, CollidableObject obj)
        {
            Vector2   tileDimensions = new Vector2(currentLevel.tileSize.X, currentLevel.tileSize.Y);
            Rectangle playerBounds   = obj.BoundingBox;

            //Determination of neighbouring tile indices from platformer demo (lab 2)
            int left   = (int)Math.Floor(playerBounds.Left / tileDimensions.X);
            int right  = (int)Math.Ceiling((playerBounds.Right / tileDimensions.X));
            int top    = (int)Math.Floor(playerBounds.Top / tileDimensions.Y);
            int bottom = (int)Math.Ceiling((playerBounds.Bottom / tileDimensions.Y));

            //For each neighbouring tile, check whether it collides with the object
            for (int i = left; i < right; i++)
            {
                for (int j = top; j < bottom; j++)
                {
                    var collisionMode = currentLevel.GetCollisionModeAt(i, j);
                    //Skip collisions with non-colliding tiles
                    if (TileCollisionMode.empty.Equals(collisionMode))
                    {
                        continue;
                    }

                    var tileBounds = currentLevel.GetBoundsAt(i, j);

                    Vector2 penDepth;
                    if (obj.CheckCollision(tileBounds, out penDepth))
                    {
                        //If a collision occured, fire relevant event

                        TileDescriptor tileDescriptor = new TileDescriptor(collisionMode, currentLevel.GetWorldPosition(i, j), new Point(i, j), tileBounds);

                        Player player = obj as Player;
                        if (player != null)
                        {
                            GameEventManager.Instance.PlayerCollision(player, tileDescriptor, penDepth);
                        }
                        else
                        {
                            GameEventManager.Instance.NonPlayerCollision(obj, tileDescriptor, penDepth);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Returns a texture2d of the given tile.
        /// Loads the Tile Stream from the map provider and turns it into a texture.
        /// If the texture is not available, it returns null.
        /// Also takes care of haven onnly MacTileCount tiles in the memory, i.e. removing textures that
        /// were not used for a long time.
        /// </summary>
        /// <param name="desc">The tile descriptor of the tile that shall be loaded.</param>
        /// <returns>A Texture2D of the given tile or null.</returns>
        private Texture2D GetTileTexture(TileDescriptor desc)
        {
            if (!_tiles.ContainsKey(desc))
            {
                Stream s = _map.GetTile(desc.Zoom, desc.Tile);

                if (s != null)
                {
                    // s will be disposed after the tile has been loaded.
                    using (s)
                    {
                        _tiles.Add(desc, Texture2D.FromStream(_device, s));
                    }

                    // Handle the max tiles in memory
                    // Add the current tile to the last place in the list

                    _loadedTiles.Remove(desc);
                    _loadedTiles.Add(desc);


                    // Now remove as many tiles from the front of the list until
                    // we have only MacLoadedTiles loaded.
                    while (_loadedTiles.Count > MaxLoadedTiles)
                    {
                        var t = _loadedTiles[0];
                        _loadedTiles.RemoveAt(0);

                        var text = _tiles[t];
                        text.Dispose();
                        _tiles.Remove(t);
                    }

                    return(_tiles[desc]);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                return(_tiles[desc]);
            }
        }
Exemple #7
0
        public WorldDescriptor GetDescriptor()
        {
            WorldDescriptor wd = new WorldDescriptor();

            wd.Width  = this.Width;
            wd.Height = this.Height;
            wd.Tiles  = new TileDescriptor[Width, Height];
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    string         tName = Grid[x, y].Name;
                    TileDescriptor td    = TileDescriptor.Create(tName);
                    wd.Tiles[x, y] = td;
                }
            }
            return(wd);
        }
Exemple #8
0
        public static World LoadWorld(WorldDescriptor worldDescriptor)
        {
            World  world = (World)GD.Load <PackedScene>("res://Scenes/World.tscn").Instance();
            Grid3D grid  = new Grid3D(world, worldDescriptor.Width, worldDescriptor.Height);

            world.AddChild(grid);

            for (int y = 0; y < worldDescriptor.Height; y++)
            {
                for (int x = 0; x < worldDescriptor.Width; x++)
                {
                    TileDescriptor tileD = worldDescriptor.Tiles[x, y];
                    Tile           tileT = CreateTile(tileD);
                    grid.SetTile(tileT, x, y, false);
                }
            }

            return(world);
        }
Exemple #9
0
        public Tile(Layer layer, TileDescriptor <SpriteInfo> tileData)
            : this(tileData)
        {
            this.Layer = layer;

            if (this.Attribute != null)
            {
                this.Attribute.ActionHandler = TileAttributeActionHandlerFactory.Create(this.Attribute);
            }

            if (this.Sprite != null)
            {
                _collisionArea = new Rect(this.Sprite.Transform.Position.X, this.Sprite.Transform.Position.Y, Settings.TileSize, Settings.TileSize);
            }
            else
            {
                _collisionArea = new Rect(this.Position.X, this.Position.Y, Settings.TileSize, Settings.TileSize);
            }

            this.Attribute?.ActionHandler?.OnInitalize(new TileAttributeArgs(this.Attribute, this));
        }
Exemple #10
0
        private static Bitmap ConvertTileToBitmap(TileDescriptor tileDesc, byte[] tmem, ushort[][] palettes)
        {
            if (Math.Floor(tileDesc.sHi - tileDesc.sLo) != tileDesc.sHi - tileDesc.sLo)
            {
                throw new Exception();
            }
            if (Math.Floor(tileDesc.tHi - tileDesc.tLo) != tileDesc.tHi - tileDesc.tLo)
            {
                throw new Exception();
            }

            // Break into lines
            int startPtrBytes = tileDesc.tmemAddressInWords * 8;
            int width         = (int)(tileDesc.sHi - tileDesc.sLo + 1);
            int height        = (int)(tileDesc.tHi - tileDesc.tLo + 1);
            int bytesPerLine  = tileDesc.wordsPerLine * 8;

            byte[] data = tmem.Subsection(startPtrBytes, bytesPerLine * height);
            ushort[]? palette = tileDesc.palette == 0 ? null : palettes[tileDesc.palette - 1];

            return(Texels.ConvertToBitmap(data, tileDesc.format, tileDesc.bitSize, width, height, bytesPerLine, true, true, palette));
        }
Exemple #11
0
 public bool HasTile(TileDescriptor tile)
 {
     return(_cache[_subCache].ContainsKey(tile));
 }
Exemple #12
0
        public List <TileDrawInfo> GetDrawTiles()
        {
            List <TileDrawInfo> info = new List <TileDrawInfo>();

            // 1. Get center point MapCoordinates
            MapVector centerMapVector = LatLonToMapPoint(Position);

            // 2. Calculate offset from center point to topleft point in map coordinates
            int topLeftXOffset = (int)((ViewBounds.Width / 2.0) / CoordinateScale);
            int topLeftYOffset = (int)((ViewBounds.Height / 2.0) / CoordinateScale);

            // 3. Calculate the top left point in map coordinates
            MapVector topLeftMapVector = new MapVector()
            {
                // real a mod b:
                // a mod b = (a % b + b) % b
                // https://de.wikipedia.org/wiki/Division_mit_Rest#Modulo

                X = (((centerMapVector.X - topLeftXOffset) % MapCoordinatesWidth) + MapCoordinatesWidth) % MapCoordinatesWidth,
                Y = (((centerMapVector.Y - topLeftYOffset) % MapCoordinatesHeight) + MapCoordinatesHeight) % MapCoordinatesHeight
            };

            // 4. Calculate Tile X/Y directly from Map Coordiantes
            MapVector tileCoord = new MapVector()
            {
                X = (int)Math.Floor(topLeftMapVector.X / (Provider.TileSize / CoordinateScale)),
                Y = (int)Math.Floor(topLeftMapVector.Y / (Provider.TileSize / CoordinateScale))
            };

            // 5. Calculate the Top-Left point of the top-left tile
            //PointXY tileMapVector = LatLonToMapPoint(Provider.GetPointForTile(Zoom, tileCoord));

            MapVector tileMapVector = new MapVector()
            {
                X = (int)(tileCoord.X * (Provider.TileSize / CoordinateScale)),
                Y = (int)(tileCoord.Y * (Provider.TileSize / CoordinateScale))
            };

            // 6. Get the offset of the top-left-point of the top-left-tile to the top-left point of the map
            // So we know if it is outside of the viewable port.
            MapVector offset = (tileMapVector - topLeftMapVector) * CoordinateScale;

            // 7. Create a rectangle for the top-left tile
            MapRectangle imgRect = new MapRectangle(offset.X, offset.Y, Provider.TileSize, Provider.TileSize);

            // 8. The top-left tile
            TileDescriptor descriptor = new TileDescriptor(Zoom, tileCoord);

            // 9. Now iterate over all viewable tiles and add them to the list
            // Handling the source and destination rectangles is done by special functions.

            int currentTileY = descriptor.Tile.Y;
            int currentTileX = descriptor.Tile.X;
            int currentRectY = imgRect.Y;
            int currentRectX = imgRect.X;

            int tileCount = Provider.GetTileCount(Zoom);

            while (currentRectX < ViewBounds.Width)
            {
                while (currentRectY < ViewBounds.Height)
                {
                    TileDescriptor desc = new TileDescriptor(descriptor.Zoom, currentTileX, currentTileY);

                    // 10. Create rectangle of the "full" tile, might lap over the borders of the viewport, i.e.
                    // having negative offsets here.
                    MapRectangle cRect = new MapRectangle(currentRectX, currentRectY, Provider.TileSize, Provider.TileSize);

                    // 11. Get the part of the tile that is being rendered.
                    MapRectangle tileSrcRect = GetSourceRectangle(cRect);

                    // 12. Get the position and the size in the viewport where the tile will be rendered.
                    MapRectangle viewDstRect = GetDestRectangle(cRect);

                    TileDrawInfo i = new TileDrawInfo();
                    i.Tile                 = new TileDescriptor(Zoom, currentTileX, currentTileY);
                    i.SourceRectangle      = tileSrcRect;
                    i.DestinationRectangle = viewDstRect;

                    info.Add(i);

                    currentRectY += Provider.TileSize;
                    currentTileY  = (currentTileY + 1) % tileCount;
                }

                currentRectY = imgRect.Y;
                currentTileY = descriptor.Tile.Y;

                currentTileX  = (currentTileX + 1) % tileCount;
                currentRectX += Provider.TileSize;
            }

            return(info);
        }
Exemple #13
0
 public Tile(Vector position)
 {
     _descriptor        = new TileDescriptor(position);
     _collisionArea     = new Rect(position.X, position.Y, Settings.TileSize, Settings.TileSize);
     _heartbeatListener = new NPCHeartbeatListener();
 }
Exemple #14
0
        public static RDPState ExecuteCommands(UVTXFile uvtx, out StringBuilder cmdsString)
        {
            RDPState rdpState = new RDPState();

            cmdsString = new StringBuilder();
            foreach (byte[] commandBytes in uvtx.displayListCommands)
            {
                byte[] bytes = commandBytes;

                string operationDesc;
                switch ((Fast3DEX2Opcode)bytes[0])
                {
                case Fast3DEX2Opcode.G_TEXTURE:
                {
                    ulong word          = bytes.ReadUInt64(0);
                    byte  mipMap        = (byte)(word.Bits(43, 3) + 1);
                    byte  tileDescIndex = (byte)word.Bits(40, 3);

                    bool  on           = word.Bit(33);
                    float scaleFactorS = bytes.ReadUInt16(4) / (float)0x10000;
                    float scaleFactorT = bytes.ReadUInt16(6) / (float)0x10000;

                    rdpState.tileToUseWhenTexturing = tileDescIndex;
                    rdpState.maxMipMapLevels        = mipMap;
                    rdpState.texturingEnabled       = on;
                    rdpState.textureScaleS          = scaleFactorS;
                    rdpState.textureScaleT          = scaleFactorT;

                    operationDesc  = "G_TEXTURE        (Set RSP texture state)";
                    operationDesc += $": tile {tileDescIndex} scale=<{scaleFactorS}, {scaleFactorT}>; mm={mipMap} on={on}";
                    break;
                }

                case Fast3DEX2Opcode.G_SetOtherMode_H:
                {
                    // TODO: actually implement this?
                    operationDesc = "G_SetOtherMode_H (Set Other Modes Hi)";

                    int length = bytes[3] + 1;
                    int shift  = 32 - length - bytes[2];

                    string str = otherModeHShiftToStr[shift];
                    byte   val = (byte)bytes.ReadUInt64(0).Bits(shift, length);

                    // TODO?: https://wiki.cloudmodding.com/oot/F3DZEX#RDP_Other_Modes.2C_Higher_Half
                    string valStr = Convert.ToString(val, 2).PadLeft(length, '0');

                    operationDesc += $": {str} = {valStr}";
                    break;
                }

                case Fast3DEX2Opcode.G_SETTILESIZE:
                {
                    ulong word = bytes.ReadUInt64(0);


                    ushort sLoRaw        = (ushort)word.Bits(44, 12);
                    ushort tLoRaw        = (ushort)word.Bits(32, 12);
                    byte   tileDescIndex = (byte)word.Bits(24, 3);
                    ushort sHiRaw        = (ushort)word.Bits(12, 12);
                    ushort tHiRaw        = (ushort)word.Bits(0, 12);

                    TileDescriptor t = rdpState.tileDescriptors[tileDescIndex];
                    t.sLo = sLoRaw / 4.0f;
                    t.tLo = tLoRaw / 4.0f;
                    t.sHi = sHiRaw / 4.0f;
                    t.tHi = tHiRaw / 4.0f;

                    float visWidth  = (t.sHi - t.sLo) + 1;
                    float visHeight = (t.tHi - t.tLo) + 1;

                    operationDesc  = "G_SETTILESIZE    (Set texture coords and size)";
                    operationDesc += $": tile {tileDescIndex} lo=({t.sLo}, {t.tLo}) hi=({t.sHi}, {t.tHi}) [[{visWidth}, {visHeight}]]";
                    break;
                }

                case Fast3DEX2Opcode.G_LOADBLOCK:
                {
                    ulong word = bytes.ReadUInt64(0);

                    ushort sLo           = (ushort)word.Bits(44, 12);
                    ushort tLo           = (ushort)word.Bits(32, 12);
                    byte   tileDescIndex = (byte)word.Bits(24, 3);
                    ushort sHi           = (ushort)word.Bits(12, 12);
                    ushort dxt           = (ushort)word.Bits(0, 12);

                    if (dxt != 0)
                    {
                        throw new Exception();
                    }

                    if (sLo != 0 || tLo != 0)
                    {
                        throw new Exception();
                    }

                    if (rdpState.nextDRAMAddrForLoad == null || rdpState.bitSizeOfNextDataForLoad == null)
                    {
                        throw new Exception();
                    }

                    rdpState.tileDescriptors[tileDescIndex].sLo = sLo;
                    rdpState.tileDescriptors[tileDescIndex].tLo = tLo;
                    rdpState.tileDescriptors[tileDescIndex].sHi = sHi;
                    rdpState.tileDescriptors[tileDescIndex].tHi = dxt;         // Not 100% sure this is the correct behavior


                    int dataStart       = (int)rdpState.nextDRAMAddrForLoad;
                    int dataLengthBytes = (sHi + 1) * Texels.BitSizeToNumBytes((BitSize)rdpState.bitSizeOfNextDataForLoad);
                    int destPtr         = rdpState.tileDescriptors[tileDescIndex].tmemAddressInWords * 8;

                    // I'm assuming this is the correct behavior because if I don't do this a lot of textures have a notch at the top right
                    // (Also it would make sense given that interleaving and addresses are all done on 64-bit words
                    dataLengthBytes = (int)Math.Ceiling(dataLengthBytes / 8f) * 8;

                    // Note: technically this inaccurate, we shouldn't clamp. But the instructions read beyond the file and IDK why,
                    // it doesn't seem to serve any purpose so I assume it's a bug (or I don't understand something about how the RSP works)
                    Array.Copy(uvtx.texelData, dataStart, rdpState.tmem, destPtr, Math.Min(uvtx.texelData.Length - dataStart, dataLengthBytes));

                    operationDesc  = "G_LOADBLOCK      (Load data into TMEM (uses params set in SETTIMG))";
                    operationDesc += $": tile {tileDescIndex} sLo={sLo} tLo={tLo} sHi={sHi} dxt={dxt}";
                    break;
                }

                case Fast3DEX2Opcode.G_SETTILE:
                {
                    ulong          word = bytes.ReadUInt64(0);
                    TileDescriptor t    = new TileDescriptor
                    {
                        format             = (ColorFormat)word.Bits(53, 3),
                        bitSize            = (BitSize)word.Bits(51, 2),
                        wordsPerLine       = (ushort)word.Bits(41, 9),
                        tmemAddressInWords = (ushort)word.Bits(32, 9),
                        palette            = (byte)word.Bits(20, 4),
                        clampEnableT       = word.Bit(19),
                        mirrorEnableT      = word.Bit(18),
                        maskT         = (byte)word.Bits(14, 4),
                        shiftT        = (byte)word.Bits(10, 4),
                        clampEnableS  = word.Bit(9),
                        mirrorEnableS = word.Bit(8),
                        maskS         = (byte)word.Bits(4, 4),
                        shiftS        = (byte)word.Bits(0, 4),
                    };
                    byte tileDescIndex = (byte)word.Bits(24, 3);
                    rdpState.tileDescriptors[tileDescIndex] = t;

                    operationDesc  = "G_SETTILE        (Set texture properties)";
                    operationDesc += $": tile {tileDescIndex} fmt={t.bitSize}-bit {t.format} wordsPerLine={t.wordsPerLine} addrWords={t.tmemAddressInWords} palette={t.palette}"
                                     + $" s(clmp={t.clampEnableS} mirr={t.mirrorEnableS} mask={t.maskS} shift={t.shiftS}) t(clmp={t.clampEnableT} mirr={t.mirrorEnableT} mask={t.maskT} shift={t.shiftT})";

                    break;
                }

                case Fast3DEX2Opcode.G_SETPRIMCOLOR:
                {
                    float minLODLevel = bytes[2] / 0x100f;
                    float LODfrac     = bytes[3] / 0x100f;
                    byte  r           = bytes[4];
                    byte  g           = bytes[5];
                    byte  b           = bytes[6];
                    byte  a           = bytes[7];

                    rdpState.colorCombinerSettings.primR       = r;
                    rdpState.colorCombinerSettings.primG       = g;
                    rdpState.colorCombinerSettings.primB       = b;
                    rdpState.colorCombinerSettings.primA       = a;
                    rdpState.colorCombinerSettings.minLODLevel = minLODLevel;
                    rdpState.colorCombinerSettings.LODfrac     = LODfrac;

                    operationDesc  = "G_SETPRIMCOLOR   (Set color combiner primitive color + LOD)";
                    operationDesc += $": rgba({r}, {g}, {b}, {a}) minLOD={minLODLevel} LODfrac={LODfrac}";
                    break;
                }

                case Fast3DEX2Opcode.G_SETENVCOLOR:
                {
                    byte r = bytes[4];
                    byte g = bytes[5];
                    byte b = bytes[6];
                    byte a = bytes[7];

                    rdpState.colorCombinerSettings.envR = r;
                    rdpState.colorCombinerSettings.envG = g;
                    rdpState.colorCombinerSettings.envB = b;
                    rdpState.colorCombinerSettings.envA = a;

                    operationDesc  = "G_SETENVCOLOR    (Set color combiner environment color)";
                    operationDesc += $": rgba({r}, {g}, {b}, {a})";
                    break;
                }

                case Fast3DEX2Opcode.G_SETCOMBINE:
                    operationDesc = "G_SETCOMBINE     (Set color combiner algorithm)";
                    break;

                case Fast3DEX2Opcode.G_SETTIMG:
                {
                    ulong word = bytes.ReadUInt64(0);

                    ColorFormat format      = (ColorFormat)word.Bits(53, 3);
                    BitSize     bitSize     = (BitSize)word.Bits(51, 2);
                    uint        dramAddress = (uint)word.Bits(0, 25);

                    rdpState.nextDRAMAddrForLoad      = dramAddress;
                    rdpState.bitSizeOfNextDataForLoad = bitSize;

                    operationDesc  = "G_SETTIMG        (Set pointer to data to load + size of data)";
                    operationDesc += $": DRAM 0x{dramAddress:X8}; fmt={bitSize}-bit {format}";

                    break;
                }

                case Fast3DEX2Opcode.G_RDPLOADSYNC:
                    operationDesc = "G_RDPLOADSYNC    (Wait for texture load)";
                    break;

                case Fast3DEX2Opcode.G_RDPTILESYNC:
                    operationDesc = "G_RDPTILESYNC    (Wait for rendering + update tile descriptor attributes)";
                    break;

                case Fast3DEX2Opcode.G_ENDDL:
                    operationDesc = "G_ENDDL          (End display list)";
                    break;

                default:
                    throw new InvalidOperationException();
                }

                string bytesStr = String.Join(" ", bytes.Select(b => b.ToString("X2")));
                cmdsString.AppendLine(bytesStr + " | " + operationDesc);
            }

            return(rdpState);
        }
 private string GetFilePath(TileDescriptor tile)
 {
     return(Path.Combine(_cacheDir, SubCache, tile.Zoom.ToString(), tile.Tile.X.ToString(), $"{tile.Tile.Y}.png"));
 }
 public bool HasTile(TileDescriptor tile)
 {
     return(File.Exists(GetFilePath(tile)));
 }