mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2024-11-04 17:27:16 -05:00
226 lines
5.9 KiB
Go
226 lines
5.9 KiB
Go
package d2maprenderer
|
|
|
|
import (
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2ds1"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2fileformats/d2dt1"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2util"
|
|
)
|
|
|
|
const (
|
|
tileMinHeight int16 = 32
|
|
shadowAdjustY int32 = 80
|
|
defaultFloorTileWidth = 10
|
|
defaultFloorTileHeight = 10
|
|
)
|
|
|
|
const (
|
|
blockOffsetY = 32
|
|
tileSurfaceWidth = 160
|
|
tileSurfaceHeight = 80
|
|
)
|
|
|
|
func (mr *MapRenderer) generateTileCache() {
|
|
var err error
|
|
mr.palette, err = mr.loadPaletteForAct(d2enum.RegionIdType(mr.mapEngine.LevelType().ID))
|
|
|
|
if err != nil {
|
|
mr.Error(err.Error())
|
|
}
|
|
|
|
tiles := *mr.mapEngine.Tiles()
|
|
for idx := range tiles {
|
|
tile := &tiles[idx]
|
|
|
|
for i := range tile.Components.Floors {
|
|
if !tile.Components.Floors[i].Hidden() && tile.Components.Floors[i].Prop1 != 0 {
|
|
mr.generateFloorCache(&tile.Components.Floors[i])
|
|
}
|
|
}
|
|
|
|
for i := range tile.Components.Shadows {
|
|
if !tile.Components.Shadows[i].Hidden() && tile.Components.Shadows[i].Prop1 != 0 {
|
|
mr.generateShadowCache(&tile.Components.Shadows[i])
|
|
}
|
|
}
|
|
|
|
for i := range tile.Components.Walls {
|
|
if !tile.Components.Walls[i].Hidden() && tile.Components.Walls[i].Prop1 != 0 {
|
|
mr.generateWallCache(&tile.Components.Walls[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (mr *MapRenderer) generateFloorCache(tile *d2ds1.FloorShadowRecord) {
|
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), 0)
|
|
|
|
var tileData []*d2dt1.Tile
|
|
|
|
if tileOptions == nil {
|
|
mr.Errorf("Could not locate tile Style:%d, Seq: %d, Type: %d", tile.Style, tile.Sequence, 0)
|
|
|
|
tileData = append(tileData, &d2dt1.Tile{})
|
|
tileData[0].Width = defaultFloorTileWidth
|
|
tileData[0].Height = defaultFloorTileHeight
|
|
} else {
|
|
if !tileOptions[0].MaterialFlags.Lava {
|
|
tileData = append(tileData, &tileOptions[tile.RandomIndex])
|
|
} else {
|
|
tile.Animated = true
|
|
for i := range tileOptions {
|
|
tileData = append(tileData, &tileOptions[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
var tileIndex byte
|
|
|
|
for i := range tileData {
|
|
if tileData[i].MaterialFlags.Lava {
|
|
tileIndex = byte(tileData[i].RarityFrameIndex)
|
|
} else {
|
|
tileIndex = tile.RandomIndex
|
|
}
|
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex)
|
|
|
|
if cachedImage != nil {
|
|
return
|
|
}
|
|
|
|
tileYMinimum := int32(0)
|
|
|
|
for _, block := range tileData[i].Blocks {
|
|
tileYMinimum = d2math.MinInt32(tileYMinimum, int32(block.Y))
|
|
}
|
|
|
|
tileYOffset := d2math.AbsInt32(tileYMinimum)
|
|
tileHeight := d2math.AbsInt32(tileData[i].Height)
|
|
image := mr.renderer.NewSurface(int(tileData[i].Width), int(tileHeight))
|
|
|
|
indexData := make([]byte, tileData[i].Width*tileHeight)
|
|
d2dt1.DecodeTileGfxData(tileData[i].Blocks, &indexData, tileYOffset, tileData[i].Width)
|
|
pixels := d2util.ImgIndexToRGBA(indexData, mr.palette)
|
|
|
|
image.ReplacePixels(pixels)
|
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, 0, tileIndex, image)
|
|
}
|
|
}
|
|
|
|
func (mr *MapRenderer) generateShadowCache(tile *d2ds1.FloorShadowRecord) {
|
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), d2enum.TileShadow)
|
|
|
|
var tileData *d2dt1.Tile
|
|
|
|
if tileOptions == nil {
|
|
return
|
|
}
|
|
|
|
tileData = &tileOptions[tile.RandomIndex]
|
|
|
|
if tileData.Width == 0 || tileData.Height == 0 {
|
|
return
|
|
}
|
|
|
|
tileMinY := int32(0)
|
|
tileMaxY := int32(0)
|
|
|
|
for _, block := range tileData.Blocks {
|
|
tileMinY = d2math.MinInt32(tileMinY, int32(block.Y))
|
|
tileMaxY = d2math.MaxInt32(tileMaxY, int32(block.Y+tileMinHeight))
|
|
}
|
|
|
|
tileYOffset := -tileMinY
|
|
tileHeight := int(tileMaxY - tileMinY)
|
|
tile.YAdjust = int(tileMinY + shadowAdjustY)
|
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, d2enum.TileShadow, tile.RandomIndex)
|
|
if cachedImage != nil {
|
|
return
|
|
}
|
|
|
|
image := mr.renderer.NewSurface(int(tileData.Width), tileHeight)
|
|
|
|
indexData := make([]byte, tileData.Width*int32(tileHeight))
|
|
d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileData.Width)
|
|
pixels := d2util.ImgIndexToRGBA(indexData, mr.palette)
|
|
|
|
image.ReplacePixels(pixels)
|
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, d2enum.TileShadow, tile.RandomIndex, image)
|
|
}
|
|
|
|
func (mr *MapRenderer) generateWallCache(tile *d2ds1.WallRecord) {
|
|
tileOptions := mr.mapEngine.GetTiles(int(tile.Style), int(tile.Sequence), tile.Type)
|
|
|
|
var tileData *d2dt1.Tile
|
|
|
|
if tileOptions == nil {
|
|
return
|
|
}
|
|
|
|
tileData = &tileOptions[tile.RandomIndex]
|
|
|
|
var newTileData *d2dt1.Tile = nil
|
|
|
|
if tile.Type == d2enum.TileRightPartOfNorthCornerWall {
|
|
newTileOptions := mr.mapEngine.GetTiles(
|
|
int(tile.Style), int(tile.Sequence),
|
|
d2enum.TileLeftPartOfNorthCornerWall,
|
|
)
|
|
newTileData = &newTileOptions[tile.RandomIndex]
|
|
}
|
|
|
|
tileMinY := int32(0)
|
|
tileMaxY := int32(0)
|
|
|
|
target := tileData
|
|
|
|
if newTileData != nil && newTileData.Height < tileData.Height {
|
|
target = newTileData
|
|
}
|
|
|
|
for _, block := range target.Blocks {
|
|
tileMinY = d2math.MinInt32(tileMinY, int32(block.Y))
|
|
tileMaxY = d2math.MaxInt32(tileMaxY, int32(block.Y+blockOffsetY))
|
|
}
|
|
|
|
realHeight := d2math.MaxInt32(d2math.AbsInt32(tileData.Height), tileMaxY-tileMinY)
|
|
tileYOffset := -tileMinY
|
|
|
|
if tile.Type == d2enum.TileRoof {
|
|
tile.YAdjust = -int(tileData.RoofHeight)
|
|
} else {
|
|
tile.YAdjust = int(tileMinY) + tileSurfaceHeight
|
|
}
|
|
|
|
cachedImage := mr.getImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex)
|
|
if cachedImage != nil {
|
|
return
|
|
}
|
|
|
|
if realHeight == 0 {
|
|
mr.Error("Invalid 0 height for wall tile")
|
|
return
|
|
}
|
|
|
|
image := mr.renderer.NewSurface(tileSurfaceWidth, int(realHeight))
|
|
|
|
indexData := make([]byte, tileSurfaceWidth*realHeight)
|
|
|
|
d2dt1.DecodeTileGfxData(tileData.Blocks, &indexData, tileYOffset, tileSurfaceWidth)
|
|
|
|
if newTileData != nil {
|
|
d2dt1.DecodeTileGfxData(newTileData.Blocks, &indexData, tileYOffset, tileSurfaceWidth)
|
|
}
|
|
|
|
pixels := d2util.ImgIndexToRGBA(indexData, mr.palette)
|
|
|
|
image.ReplacePixels(pixels)
|
|
|
|
mr.setImageCacheRecord(tile.Style, tile.Sequence, tile.Type, tile.RandomIndex, image)
|
|
}
|