예제 #1
0
        public unsafe void DrawMapCell(int xCell, int yCell, int xPixel, int yPixel, MPQDS1 mapData, int main_index, int sub_index, Palette palette, int orientation)
        {
            var tiles = mapData.LookupTable.Where(x =>
                                                  x.MainIndex == main_index &&
                                                  x.SubIndex == sub_index &&
                                                  (orientation == -1 || x.Orientation == orientation)).Select(x => x.TileRef);

            if (!tiles.Any())
            {
                return;
            }
            //throw new ApplicationException("Invalid tile id found!");


            // TODO: This isn't good.. should be remembered in the map engine layer
            MPQDT1Tile tile = null;

            if (tiles.Count() > 0)
            {
                var totalRarity = tiles.Sum(q => q.RarityOrFrameIndex);
                var random      = new Random(gameState.Seed + xCell + (mapData.Width * yCell));
                var x           = random.Next(totalRarity);
                var z           = 0;
                foreach (var t in tiles)
                {
                    z += t.RarityOrFrameIndex;
                    if (x <= z)
                    {
                        tile = t;
                        break;
                    }
                }
            }
            else
            {
                tile = tiles.First();
            }

            // This WILL happen to you
            if (tile.Width == 0 || tile.Height == 0)
            {
                return;
            }

            if (mapDataLookup.ContainsKey(mapData.Id))
            {
                var lookupDetails = mapDataLookup[mapData.Id].FirstOrDefault(x => x.TileId == tile.Id);
                if (lookupDetails != null)
                {
                    var dx = new SDL.SDL_Rect {
                        x = xPixel - lookupDetails.OffX, y = yPixel - lookupDetails.OffY, w = lookupDetails.FrameWidth, h = lookupDetails.FrameHeight
                    };
                    SDL.SDL_RenderCopy(renderer, lookupDetails.Texture, ref lookupDetails.SrcRect, ref dx);
                    return;
                }
            }


            var minX  = tile.Blocks.Min(x => x.PositionX);
            var minY  = tile.Blocks.Min(x => x.PositionY);
            var maxX  = tile.Blocks.Max(x => x.PositionX + 32);
            var maxY  = tile.Blocks.Max(x => x.PositionY + 32);
            var diffX = maxX - minX;
            var diffY = maxY - minY;

            var offX = -minX;
            var offy = -minY;

            var frameSize = new Size(diffX, Math.Abs(diffY));

            var srcRect = new SDL.SDL_Rect {
                x = 0, y = 0, w = frameSize.Width, h = Math.Abs(frameSize.Height)
            };
            var frameSizeMax = diffX * Math.Abs(diffY);


            var texId = SDL.SDL_CreateTexture(renderer, SDL.SDL_PIXELFORMAT_ARGB8888, (int)SDL.SDL_TextureAccess.SDL_TEXTUREACCESS_STREAMING, frameSize.Width, frameSize.Height);

            SDL.SDL_SetTextureBlendMode(texId, SDL.SDL_BlendMode.SDL_BLENDMODE_BLEND);


            if (SDL.SDL_LockTexture(texId, IntPtr.Zero, out IntPtr pixels, out int pitch) != 0)
            {
                log.Error("Could not lock texture for map rendering");
                return;
            }
            try
            {
                UInt32 *data = (UInt32 *)pixels;

                var pitchChange = (pitch / 4);

                for (var i = 0; i < frameSize.Height * pitchChange; i++)
                {
                    data[i] = 0x0;
                }


                foreach (var block in tile.Blocks)
                {
                    var index = block.PositionX + offX + ((block.PositionY + offy) * pitchChange);
                    var xx    = 0;
                    var yy    = 0;
                    foreach (var colorIndex in block.PixelData)
                    {
                        try
                        {
                            if (colorIndex == 0)
                            {
                                continue;
                            }
                            var color = palette.Colors[colorIndex];

                            if (color > 0)
                            {
                                data[index] = color;
                            }
                        }
                        finally
                        {
                            index++;
                            xx++;
                            if (xx == 32)
                            {
                                index -= 32;
                                index += pitchChange;
                                xx     = 0;
                                yy++;
                            }
                        }
                    }
                }
            }
            finally
            {
                SDL.SDL_UnlockTexture(texId);
            }

            if (!mapDataLookup.ContainsKey(mapData.Id))
            {
                mapDataLookup[mapData.Id] = new List <_MapDataLookup>();
            }

            var lookup = new _MapDataLookup
            {
                FrameHeight = frameSize.Height,
                FrameWidth  = frameSize.Width,
                OffX        = offX,
                OffY        = offy,
                SrcRect     = srcRect,
                TileId      = tile.Id,
                Texture     = texId
            };

            mapDataLookup[mapData.Id].Add(lookup);

            var dr = new SDL.SDL_Rect {
                x = xPixel - lookup.OffX, y = yPixel - lookup.OffY, w = lookup.FrameWidth, h = lookup.FrameHeight
            };

            SDL.SDL_RenderCopy(renderer, lookup.Texture, ref lookup.SrcRect, ref dr);
        }
예제 #2
0
        private MapCellInfo GetMapCellInfo(IMapInfo map, int cellX, int cellY, MPQDS1TileProps props, eRenderCellType cellType, byte orientation)
        {
            if (props.Prop1 == 0)
            {
                return(null);
            }

            if (!map.CellInfo.ContainsKey(cellType))
            {
                map.CellInfo[cellType] = new MapCellInfo[map.FileData.Width * map.FileData.Height];
            }

            var cellInfo = map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)];

            if (cellInfo != null && (cellInfo.Ignore || !cellInfo.Tile.Animated))
            {
                return(cellInfo.Ignore ? null : cellInfo);
            }

            var mainIndex = (props.Prop3 >> 4) + ((props.Prop4 & 0x03) << 4);
            var subIndex  = props.Prop2;

            if (orientation == 0)
            {
                // Floor or Shadow
                if (cellType != eRenderCellType.Floor && cellType != eRenderCellType.Shadow)
                {
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }
            else if (orientation == 10 || orientation == 11)
            {
                if (cellType != eRenderCellType.WallNormal)
                {
                    // Special tile
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }
            else if (orientation == 14)
            {
                // Walls (objects?) with precedent shadows
                if (cellType != eRenderCellType.WallNormal)
                {
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }
            else if (orientation < 15)
            {
                // Upper walls
                if (cellType != eRenderCellType.WallNormal)
                {
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }
            else if (orientation == 15)
            {
                // Roof
                if (cellType != eRenderCellType.Roof)
                {
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }
            else
            {
                // Lower Walls
                if (cellType != eRenderCellType.WallLower)
                {
                    map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                        Ignore = true
                    };
                    return(null);
                }
            }

            IEnumerable <MPQDT1Tile> tiles = Enumerable.Empty <MPQDT1Tile>();

            tiles = map.FileData.LookupTable
                    .Where(x => x.MainIndex == mainIndex && x.SubIndex == subIndex && x.Orientation == orientation)
                    .Select(x => x.TileRef);

            if (tiles == null || !tiles.Any())
            {
                log.Error($"Could not find tile [{mainIndex}:{subIndex}:{orientation}]!");
                map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                    Ignore = true
                };
                return(null);
            }

            MPQDT1Tile tile = null;

            if (tiles.First().Animated)
            {
#if DEBUG
                if (!tiles.All(x => x.Animated))
                {
                    throw new OpenDiablo2Exception("Some tiles are animated and some aren't...");
                }
#endif
                var frameIndex = (int)Math.Floor(tiles.Count() * animationTime);
                tile = tiles.ElementAt(frameIndex);
            }
            else
            {
                if (tiles.Any())
                {
                    var totalRarity = tiles.Sum(q => q.RarityOrFrameIndex);
                    var random      = new Random(Seed + cellX + (map.FileData.Width * cellY));
                    var x           = random.Next(totalRarity);
                    var z           = 0;
                    foreach (var t in tiles)
                    {
                        z += t.RarityOrFrameIndex;
                        if (x <= z)
                        {
                            tile = t;
                            break;
                        }
                    }

                    if (tile.Animated)
                    {
                        throw new OpenDiablo2Exception("Why are we randomly finding an animated tile? Something's wrong here.");
                    }
                }
                else
                {
                    tile = tiles.First();
                }
            }


            // This WILL happen to you
            if (tile.Width == 0 || tile.Height == 0)
            {
                map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                    Ignore = true
                };
                return(null);
            }


            if (tile.BlockDataLength == 0)
            {
                map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = new MapCellInfo {
                    Ignore = true
                };
                return(null); // Why is this a thing?
            }


            var mapCellInfo = mapDataLookup.FirstOrDefault(x => x.Tile.Id == tile.Id);
            if (mapCellInfo == null)
            {
                mapCellInfo = renderWindow.CacheMapCell(tile, cellType);
                mapDataLookup.Add(mapCellInfo);
            }

            map.CellInfo[cellType][cellX + (cellY * map.FileData.Width)] = mapCellInfo;
            return(mapCellInfo);
        }