1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-17 18:06:03 -05:00

Lots of map rendering changes.

This commit is contained in:
Tim Sarbin 2019-11-01 22:12:07 -04:00
parent 07709e2ddf
commit b05e887d8a
4 changed files with 173 additions and 86 deletions

View File

@ -24,6 +24,14 @@ func MaxInt32(a, b int32) int32 {
return b
}
func NextPow2(x int32) int32 {
result := int32(1)
for result < x {
result *= 2
}
return result
}
func AbsInt32(a int32) int32 {
if a < 0 {
return -a

View File

@ -51,25 +51,57 @@ func (v *Engine) Render(target *ebiten.Image) {
for x := 0; x < int(v.regions[0].Region.TileWidth); x++ {
tile := v.regions[0].Region.DS1.Tiles[y][x]
for i := range tile.Floors {
v.regions[0].Region.RenderTile(400+offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeFloors, i, target)
if !tile.Floors[i].Hidden && tile.Floors[i].Prop1 != 0 {
v.regions[0].Region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeFloors, i, target)
}
}
offX += 80
offY += 40
}
}
for y := 0; y < int(v.regions[0].Region.TileHeight); y++ {
offX := -(y * 80)
offY := y * 40
for x := 0; x < int(v.regions[0].Region.TileWidth); x++ {
tile := v.regions[0].Region.DS1.Tiles[y][x]
for i := range tile.Shadows {
if tile.Shadows[i].Hidden || tile.Shadows[i].Prop1 == 0 {
continue
}
v.regions[0].Region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeShadows, i, target)
}
offX += 80
offY += 40
}
}
for y := 0; y < int(v.regions[0].Region.TileHeight); y++ {
offX := -(y * 80)
offY := y * 40
for x := 0; x < int(v.regions[0].Region.TileWidth); x++ {
tile := v.regions[0].Region.DS1.Tiles[y][x]
for i := range tile.Walls {
// TODO: render back walls, then character, then fore walls
v.regions[0].Region.RenderTile(400+offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeWalls, i, target)
if tile.Walls[i].Hidden || tile.Walls[i].Orientation == 15 || tile.Walls[i].Orientation == 10 || tile.Walls[i].Orientation == 11 || tile.Walls[i].Orientation == 0 {
continue
}
v.regions[0].Region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeWalls, i, target)
}
offX += 80
offY += 40
}
}
for y := 0; y < int(v.regions[0].Region.TileHeight); y++ {
offX := -(y * 80)
offY := y * 40
for x := 0; x < int(v.regions[0].Region.TileWidth); x++ {
tile := v.regions[0].Region.DS1.Tiles[y][x]
for i := range tile.Walls {
if tile.Walls[i].Hidden || tile.Walls[i].Orientation != 15 {
continue
}
v.regions[0].Region.RenderTile(offX+int(v.OffsetX), offY+int(v.OffsetY), x, y, RegionLayerTypeWalls, i, target)
}
offX += 80
offY += 40
}
}
}

View File

@ -1,6 +1,8 @@
package Map
import (
"image/color"
"log"
"math"
"math/rand"
"strconv"
@ -26,14 +28,17 @@ type Region struct {
Tiles []Tile
DS1 *DS1
Palette Common.PaletteRec
TileCache map[uint32]*TileCacheRecord
FloorCache map[uint32]*TileCacheRecord
ShadowCache map[uint32]*TileCacheRecord
WallCache map[uint32]*TileCacheRecord
}
type RegionLayerType int
const (
RegionLayerTypeFloors RegionLayerType = 0
RegionLayerTypeWalls RegionLayerType = 1
RegionLayerTypeFloors RegionLayerType = 0
RegionLayerTypeWalls RegionLayerType = 1
RegionLayerTypeShadows RegionLayerType = 2
)
type RegionIdType int
@ -81,7 +86,9 @@ func LoadRegion(seed rand.Source, levelType RegionIdType, levelPreset int, fileP
levelType: Common.LevelTypes[levelType],
levelPreset: Common.LevelPresets[levelPreset],
Tiles: make([]Tile, 0),
TileCache: make(map[uint32]*TileCacheRecord),
FloorCache: make(map[uint32]*TileCacheRecord),
ShadowCache: make(map[uint32]*TileCacheRecord),
WallCache: make(map[uint32]*TileCacheRecord),
}
result.Palette = Common.Palettes[PaletteDefs.PaletteType("act"+strconv.Itoa(int(result.levelType.Act)))]
//\bm := result.levelPreset.Dt1Mask
@ -122,6 +129,8 @@ func (v *Region) RenderTile(offsetX, offsetY, tileX, tileY int, layerType Region
v.renderFloor(v.DS1.Tiles[tileY][tileX].Floors[layerIndex], offsetX, offsetY, target)
case RegionLayerTypeWalls:
v.renderWall(v.DS1.Tiles[tileY][tileX].Walls[layerIndex], offsetX, offsetY, target)
case RegionLayerTypeShadows:
v.renderShadow(v.DS1.Tiles[tileY][tileX].Shadows[layerIndex], offsetX, offsetY, target)
}
}
@ -138,17 +147,14 @@ func (v *Region) getTile(mainIndex, subIndex, orientation int32) *Tile {
}
func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
if tile.Hidden {
return
}
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8)
tileCache := v.TileCache[tileCacheIndex]
if tileCache == nil {
v.TileCache[tileCacheIndex] = v.generateFloorCache(tile)
tileCache = v.TileCache[tileCacheIndex]
}
if tileCache == nil {
return
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8)
tileCache, exists := v.FloorCache[tileCacheIndex]
if !exists {
v.FloorCache[tileCacheIndex] = v.generateFloorCache(tile)
tileCache = v.FloorCache[tileCacheIndex]
if tileCache == nil {
log.Fatal("Could not load floor tile")
}
}
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
@ -156,30 +162,38 @@ func (v *Region) renderFloor(tile FloorShadowRecord, offsetX, offsetY int, targe
}
func (v *Region) renderWall(tile WallRecord, offsetX, offsetY int, target *ebiten.Image) {
if tile.Hidden {
return
}
if tile.Prop1 == 0 {
return
}
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + (uint32(tile.Orientation))
tileCache := v.TileCache[tileCacheIndex]
if tileCache == nil {
v.TileCache[tileCacheIndex] = v.generateWallCache(tile)
// TODO: Temporary hack
if v.TileCache[tileCacheIndex] == nil {
return
tileCacheIndex := (uint32(tile.MainIndex) << 16) | (uint32(tile.SubIndex) << 8) | (uint32(tile.Orientation))
tileCache, exists := v.WallCache[tileCacheIndex]
if !exists {
v.WallCache[tileCacheIndex] = v.generateWallCache(tile)
if v.WallCache[tileCacheIndex] == nil {
log.Fatal("Could not generate wall")
}
tileCache = v.TileCache[tileCacheIndex]
tileCache = v.WallCache[tileCacheIndex]
}
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
target.DrawImage(tileCache.Image, opts)
}
func (v *Region) decodeFloorData(blocks []Block, pixels []byte, tileYOffset int32, tileWidth int32) {
func (v *Region) renderShadow(tile FloorShadowRecord, offsetX, offsetY int, target *ebiten.Image) {
tileCacheIndex := (uint32(tile.MainIndex) << 16) + (uint32(tile.SubIndex) << 8) + 0
tileCache, exists := v.ShadowCache[tileCacheIndex]
if !exists {
v.ShadowCache[tileCacheIndex] = v.generateShadowCache(tile)
tileCache = v.ShadowCache[tileCacheIndex]
if tileCache == nil {
log.Fatal("Could not load shadow tile")
}
}
opts := &ebiten.DrawImageOptions{}
opts.GeoM.Translate(float64(offsetX+tileCache.XOffset), float64(offsetY+tileCache.YOffset))
opts.ColorM = Common.ColorToColorM(color.RGBA{255, 255, 255, 160})
target.DrawImage(tileCache.Image, opts)
}
func (v *Region) decodeTileGfxData(blocks []Block, pixels []byte, tileYOffset int32, tileWidth int32) {
for _, block := range blocks {
// TODO: Move this to a less stupid place
if block.Format == BlockFormatIsometric {
// 3D isometric decoding
xjump := []int32{14, 12, 10, 8, 6, 4, 2, 0, 2, 4, 6, 8, 10, 12, 14}
@ -198,12 +212,11 @@ func (v *Region) decodeFloorData(blocks []Block, pixels []byte, tileYOffset int3
colorIndex := block.EncodedData[idx]
if colorIndex != 0 {
pixelColor := v.Palette.Colors[colorIndex]
pixels[(4 * (((blockY + y) * tileWidth) + (blockX + x)))] = pixelColor.R
pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+1] = pixelColor.G
pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+2] = pixelColor.B
pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+3] = 255
} else {
pixels[(4*(((blockY+y)*tileWidth)+(blockX+x)))+3] = 0
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
pixels[offset] = pixelColor.R
pixels[offset+1] = pixelColor.G
pixels[offset+2] = pixelColor.B
pixels[offset+3] = 255
}
x++
n--
@ -220,27 +233,27 @@ func (v *Region) decodeFloorData(blocks []Block, pixels []byte, tileYOffset int3
idx := 0
length := block.Length
for length > 0 {
length -= 2
if (block.EncodedData[idx] + block.EncodedData[idx+1]) == 0 {
x = 0
y++
idx += 2
continue
}
length -= int32(block.EncodedData[idx+1])
x += int32(block.EncodedData[idx])
b1 := block.EncodedData[idx]
b2 := block.EncodedData[idx+1]
idx += 2
length -= 2
if (b1 | b2) == 0 {
x = 0
y++
continue
}
x += int32(b1)
length -= int32(b2)
for b2 > 0 {
colorIndex := block.EncodedData[idx]
if colorIndex != 0 {
pixelColor := v.Palette.Colors[colorIndex]
pixels[(4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x)))] = pixelColor.R
pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+1] = pixelColor.G
pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+2] = pixelColor.B
pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+3] = 255
} else {
pixels[(4*(((blockY+y+tileYOffset)*tileWidth)+(blockX+x)))+3] = 0
offset := 4 * (((blockY + y + tileYOffset) * tileWidth) + (blockX + x))
pixels[offset] = pixelColor.R
pixels[offset+1] = pixelColor.G
pixels[offset+2] = pixelColor.B
pixels[offset+3] = 255
}
idx++
x++
@ -254,7 +267,7 @@ func (v *Region) decodeFloorData(blocks []Block, pixels []byte, tileYOffset int3
func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord {
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 0)
if tileData == nil {
return nil
log.Fatalf("Could not locate tile Idx:%d, Sub: %d, Ori: %d", tile.MainIndex, tile.SubIndex, 0)
}
tileYMinimum := int32(0)
for _, block := range tileData.Blocks {
@ -264,37 +277,73 @@ func (v *Region) generateFloorCache(tile FloorShadowRecord) *TileCacheRecord {
tileHeight := Common.AbsInt32(tileData.Height)
image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest)
pixels := make([]byte, 4*tileData.Width*tileHeight)
v.decodeFloorData(tileData.Blocks, pixels, tileYOffset, tileData.Width)
v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, tileData.Width)
image.ReplacePixels(pixels)
return &TileCacheRecord{image, 0, 0}
}
func (v *Region) generateShadowCache(tile FloorShadowRecord) *TileCacheRecord {
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), 13)
if tileData == nil {
return nil
}
tileMinY := int32(0)
tileMaxY := int32(0)
for _, block := range tileData.Blocks {
tileMinY = Common.MinInt32(tileMinY, int32(block.Y))
tileMaxY = Common.MaxInt32(tileMaxY, int32(block.Y+32))
}
tileYOffset := -tileMinY
tileHeight := int(tileMaxY - tileMinY)
image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest)
pixels := make([]byte, 4*tileData.Width*int32(tileHeight))
v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, tileData.Width)
image.ReplacePixels(pixels)
return &TileCacheRecord{image, 0, int(tileMinY) + 80}
}
func (v *Region) generateWallCache(tile WallRecord) *TileCacheRecord {
tileData := v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(tile.Orientation))
if tileData == nil {
return nil
}
tileYMinimum := int32(0)
for _, block := range tileData.Blocks {
tileYMinimum = Common.MinInt32(tileYMinimum, int32(block.Y))
var newTileData *Tile = nil
if tile.Orientation == 3 {
newTileData = v.getTile(int32(tile.MainIndex), int32(tile.SubIndex), int32(4))
}
tileMinY := int32(0)
tileMaxY := int32(0)
target := tileData
if newTileData != nil && newTileData.Height < tileData.Height {
target = newTileData
}
for _, block := range target.Blocks {
tileMinY = Common.MinInt32(tileMinY, int32(block.Y))
tileMaxY = Common.MaxInt32(tileMaxY, int32(block.Y+32))
}
realHeight := Common.MaxInt32(Common.AbsInt32(tileData.Height), tileMaxY-tileMinY)
tileYOffset := -tileMinY
//tileHeight := int(tileMaxY - tileMinY)
image, _ := ebiten.NewImage(160, int(realHeight), ebiten.FilterNearest)
pixels := make([]byte, 4*160*realHeight)
v.decodeTileGfxData(tileData.Blocks, pixels, tileYOffset, 160)
if newTileData != nil {
v.decodeTileGfxData(newTileData.Blocks, pixels, tileYOffset, 160)
}
tileYOffset := -tileYMinimum
tileHeight := Common.AbsInt32(tileData.Height)
image, _ := ebiten.NewImage(int(tileData.Width), int(tileHeight), ebiten.FilterNearest)
pixels := make([]byte, 4*tileData.Width*tileHeight)
v.decodeFloorData(tileData.Blocks, pixels, tileYOffset, tileData.Width)
image.ReplacePixels(pixels)
yAdjust := 0
if tile.Orientation == 15 {
if tile.Orientation > 15 {
// Lower Walls
yAdjust = 80
} else if tile.Orientation == 15 {
// Roof
yAdjust = -int(tileData.RoofHeight)
} else if tile.Orientation > 15 {
// Lower walls
yAdjust = int(tileYMinimum) + 80
} else {
// Upper Walls
yAdjust = int(tileYMinimum) + 80
// Upper Walls, Special Tiles
yAdjust = int(tileMinY) + 80
}
image.ReplacePixels(pixels)
return &TileCacheRecord{
image,
0,

View File

@ -13,9 +13,8 @@ type MapEngineTest struct {
soundManager *Sound.Manager
fileProvider Common.FileProvider
sceneProvider SceneProvider
//region *Map.Region
gameState *Common.GameState
mapEngine *Map.Engine
gameState *Common.GameState
mapEngine *Map.Engine
}
func CreateMapEngineTest(
@ -40,20 +39,19 @@ func (v *MapEngineTest) Load() []func() {
return []func(){
func() {
v.mapEngine = Map.CreateMapEngine(v.gameState, v.soundManager, v.fileProvider)
//v.mapEngine.GenerateMap(Map.RegionAct2Harem, 353)
v.mapEngine.GenerateMap(Map.RegionAct1Town, 1)
//v.mapEngine.GenerateMap(Map.RegionAct1Tristram, 300)
//v.mapEngine.GenerateMap(Map.RegionAct3Town, 529)
//v.mapEngine.GenerateMap(Map.RegionAct1Cathedral, 257)
//v.mapEngine.GenerateMap(Map.RegionAct5IceCaves, 1038)
//v.mapEngine.GenerateMap(Map.RegionAct2Town, 301) // Broken rendering
//v.mapEngine.GenerateMap(Map.RegionAct2Harem, 353)
//v.mapEngine.GenerateMap(Map.RegionAct3Town, 529)
//v.mapEngine.GenerateMap(Map.RegionAct3Jungle, 574)
// Completely broken ----------------------------------------------
//v.mapEngine.GenerateMap(Map.RegonAct5Town, 863) // CRASHES
// v.mapEngine.GenerateMap(Map.RegionAct5Siege, 879) // CRASHES
//v.mapEngine.GenerateMap(Map.RegonAct5Town, 863)
//v.mapEngine.GenerateMap(Map.RegionAct5IceCaves, 1038)
//v.mapEngine.GenerateMap(Map.RegionAct5Siege, 879)
//v.mapEngine.GenerateMap(Map.RegionAct5Lava, 1057) // PALETTE ISSUE
// v.mapEngine.GenerateMap(Map.RegionAct2Town, 301) // Really broken rendering
//v.mapEngine.GenerateMap(Map.RegionAct5Barricade, 880)
},
}