2020-06-21 18:40:37 -04:00
|
|
|
package d2maprenderer
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common"
|
2020-07-03 14:00:56 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
2020-06-21 18:40:37 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
|
2020-07-08 17:46:45 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
|
2020-06-21 18:40:37 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
func (mr *MapRenderer) generateTileCache() {
|
2020-06-29 12:37:11 -04:00
|
|
|
mr.palette, _ = loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
2020-06-21 18:40:37 -04:00
|
|
|
mapEngineSize := mr.mapEngine.Size()
|
|
|
|
|
|
|
|
for idx, tile := range *mr.mapEngine.Tiles() {
|
|
|
|
tileX := idx % mapEngineSize.Width
|
|
|
|
tileY := (idx - tileX) / mapEngineSize.Width
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for i := range tile.Floors {
|
|
|
|
if !tile.Floors[i].Hidden && tile.Floors[i].Prop1 != 0 {
|
|
|
|
mr.generateFloorCache(&tile.Floors[i], tileX, tileY)
|
|
|
|
}
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for i := range tile.Shadows {
|
|
|
|
if !tile.Shadows[i].Hidden && tile.Shadows[i].Prop1 != 0 {
|
|
|
|
mr.generateShadowCache(&tile.Shadows[i], tileX, tileY)
|
|
|
|
}
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for i := range tile.Walls {
|
|
|
|
if !tile.Walls[i].Hidden && tile.Walls[i].Prop1 != 0 {
|
|
|
|
mr.generateWallCache(&tile.Walls[i], tileX, tileY)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
|
|
|
|
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), 0)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileData []*d2dt1.Tile
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileIndex byte
|
|
|
|
|
|
|
|
if tileOptions == nil {
|
|
|
|
log.Printf("Could not locate tile Style:%d, Seq: %d, Type: %d\n", tile.Style, tile.Sequence, 0)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
tileData = append(tileData, &d2dt1.Tile{})
|
|
|
|
tileData[0].Width = 10
|
|
|
|
tileData[0].Height = 10
|
|
|
|
} else {
|
|
|
|
if !tileOptions[0].MaterialFlags.Lava {
|
|
|
|
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed())
|
|
|
|
tileData = append(tileData, &tileOptions[tileIndex])
|
|
|
|
} else {
|
|
|
|
tile.Animated = true
|
|
|
|
for i := range tileOptions {
|
|
|
|
tileData = append(tileData, &tileOptions[i])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range tileData {
|
|
|
|
if !tileData[i].MaterialFlags.Lava {
|
|
|
|
tile.RandomIndex = tileIndex
|
|
|
|
} else {
|
|
|
|
tileIndex = byte(tileData[i].RarityFrameIndex)
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
if cachedImage != nil {
|
|
|
|
return
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
tileYMinimum := int32(0)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for _, block := range tileData[i].Blocks {
|
|
|
|
tileYMinimum = d2common.MinInt32(tileYMinimum, int32(block.Y))
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
tileYOffset := d2common.AbsInt32(tileYMinimum)
|
|
|
|
tileHeight := d2common.AbsInt32(tileData[i].Height)
|
2020-07-06 21:26:08 -04:00
|
|
|
image, _ := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight), d2enum.FilterNearest)
|
2020-07-08 17:46:45 -04:00
|
|
|
indexData := make([]byte, tileData[i].Width*tileHeight)
|
|
|
|
mr.decodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width)
|
|
|
|
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
|
|
|
|
|
2020-07-03 14:00:56 -04:00
|
|
|
_ = image.ReplacePixels(pixels)
|
2020-06-21 18:40:37 -04:00
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord, tileX, tileY int) {
|
|
|
|
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), 13)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileIndex byte
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileData *d2dt1.Tile
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
if tileOptions == nil {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed())
|
|
|
|
tileData = &tileOptions[tileIndex]
|
|
|
|
}
|
|
|
|
|
|
|
|
if tileData.Width == 0 || tileData.Height == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
tile.RandomIndex = tileIndex
|
|
|
|
tileMinY := int32(0)
|
|
|
|
tileMaxY := int32(0)
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for _, block := range tileData.Blocks {
|
|
|
|
tileMinY = d2common.MinInt32(tileMinY, int32(block.Y))
|
|
|
|
tileMaxY = d2common.MaxInt32(tileMaxY, int32(block.Y+32))
|
|
|
|
}
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
tileYOffset := -tileMinY
|
|
|
|
tileHeight := int(tileMaxY - tileMinY)
|
|
|
|
tile.YAdjust = int(tileMinY + 80)
|
|
|
|
|
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex)
|
|
|
|
if cachedImage != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
image, _ := mr.renderer.NewSurface(int(tileData.Width), tileHeight, d2enum.FilterNearest)
|
2020-07-08 17:46:45 -04:00
|
|
|
indexData := make([]byte, tileData.Width*int32(tileHeight))
|
|
|
|
mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width)
|
|
|
|
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
|
2020-07-03 14:00:56 -04:00
|
|
|
_ = image.ReplacePixels(pixels)
|
2020-06-21 18:40:37 -04:00
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, 13, tileIndex, image)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord, tileX, tileY int) {
|
|
|
|
tileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), int32(tile.Type))
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileIndex byte
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var tileData *d2dt1.Tile
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
if tileOptions == nil {
|
|
|
|
return
|
|
|
|
} else {
|
|
|
|
tileIndex = mr.getRandomTile(tileOptions, tileX, tileY, mr.mapEngine.Seed())
|
|
|
|
tileData = &tileOptions[tileIndex]
|
|
|
|
}
|
|
|
|
|
|
|
|
tile.RandomIndex = tileIndex
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
var newTileData *d2dt1.Tile = nil
|
|
|
|
|
|
|
|
if tile.Type == 3 {
|
|
|
|
newTileOptions := mr.mapEngine.GetTiles(int32(tile.Style), int32(tile.Sequence), int32(4))
|
|
|
|
newTileIndex := mr.getRandomTile(newTileOptions, tileX, tileY, mr.mapEngine.Seed())
|
|
|
|
newTileData = &newTileOptions[newTileIndex]
|
|
|
|
}
|
|
|
|
|
|
|
|
tileMinY := int32(0)
|
|
|
|
tileMaxY := int32(0)
|
|
|
|
|
|
|
|
target := tileData
|
|
|
|
|
|
|
|
if newTileData != nil && newTileData.Height < tileData.Height {
|
|
|
|
target = newTileData
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, block := range target.Blocks {
|
|
|
|
tileMinY = d2common.MinInt32(tileMinY, int32(block.Y))
|
|
|
|
tileMaxY = d2common.MaxInt32(tileMaxY, int32(block.Y+32))
|
|
|
|
}
|
|
|
|
|
|
|
|
realHeight := d2common.MaxInt32(d2common.AbsInt32(tileData.Height), tileMaxY-tileMinY)
|
|
|
|
tileYOffset := -tileMinY
|
2020-07-09 16:11:01 -04:00
|
|
|
/*tileHeight := int(tileMaxY - tileMinY)*/
|
2020-06-21 18:40:37 -04:00
|
|
|
|
|
|
|
if tile.Type == 15 {
|
|
|
|
tile.YAdjust = -int(tileData.RoofHeight)
|
|
|
|
} else {
|
|
|
|
tile.YAdjust = int(tileMinY) + 80
|
|
|
|
}
|
|
|
|
|
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tileIndex)
|
|
|
|
if cachedImage != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if realHeight == 0 {
|
|
|
|
log.Printf("Invalid 0 height for wall tile")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-06 21:26:08 -04:00
|
|
|
image, _ := mr.renderer.NewSurface(160, int(realHeight), d2enum.FilterNearest)
|
2020-07-08 17:46:45 -04:00
|
|
|
indexData := make([]byte, 160*realHeight)
|
2020-07-03 14:00:56 -04:00
|
|
|
|
2020-07-08 17:46:45 -04:00
|
|
|
mr.decodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, 160)
|
2020-06-21 18:40:37 -04:00
|
|
|
|
|
|
|
if newTileData != nil {
|
2020-07-08 17:46:45 -04:00
|
|
|
mr.decodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, 160)
|
2020-06-21 18:40:37 -04:00
|
|
|
}
|
|
|
|
|
2020-07-08 17:46:45 -04:00
|
|
|
pixels := d2asset.ImgIndexToRGBA(indexData, mr.palette)
|
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
if err := image.ReplacePixels(pixels); err != nil {
|
|
|
|
log.Panicf(err.Error())
|
|
|
|
}
|
|
|
|
|
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tileIndex, image)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (mr *MapRenderer) getRandomTile(tiles []d2dt1.Tile, x, y int, seed int64) byte {
|
|
|
|
/* Walker's Alias Method for weighted random selection
|
|
|
|
* with xorshifting for random numbers */
|
|
|
|
|
|
|
|
var tileSeed uint64
|
|
|
|
tileSeed = uint64(seed) + uint64(x)
|
2020-06-29 12:37:11 -04:00
|
|
|
tileSeed *= uint64(y) + uint64(mr.mapEngine.LevelType().ID)
|
2020-06-21 18:40:37 -04:00
|
|
|
|
|
|
|
tileSeed ^= tileSeed << 13
|
|
|
|
tileSeed ^= tileSeed >> 17
|
|
|
|
tileSeed ^= tileSeed << 5
|
|
|
|
|
|
|
|
weightSum := 0
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for _, tile := range tiles {
|
|
|
|
weightSum += int(tile.RarityFrameIndex)
|
|
|
|
}
|
|
|
|
|
|
|
|
if weightSum == 0 {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
random := tileSeed % uint64(weightSum)
|
|
|
|
|
|
|
|
sum := 0
|
2020-07-09 16:11:01 -04:00
|
|
|
|
2020-06-21 18:40:37 -04:00
|
|
|
for i, tile := range tiles {
|
|
|
|
sum += int(tile.RarityFrameIndex)
|
|
|
|
if sum >= int(random) {
|
|
|
|
return byte(i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This return shouldn't be hit
|
|
|
|
return 0
|
|
|
|
}
|