OpenDiablo2/d2common/d2fileformats/d2ds1/ds1_layers.go

433 lines
8.2 KiB
Go

package d2ds1
const (
maxWallLayers = 4
maxOrientationLayers = 4
maxFloorLayers = 2
maxShadowLayers = 1
maxSubstitutionLayers = 1
)
type layerGroupType int
const (
floorLayerGroup layerGroupType = iota
wallLayerGroup
orientationLayerGroup
shadowLayerGroup
substitutionLayerGroup
)
type layerGroup []*layer
type ds1Layers struct {
width, height int
Floors layerGroup
Walls layerGroup
Orientations layerGroup
Shadows layerGroup
Substitutions layerGroup
}
func (l *ds1Layers) ensureInit() {
if l.Floors == nil {
l.Floors = make(layerGroup, 0)
}
if l.Walls == nil {
l.Walls = make(layerGroup, 0)
}
if l.Orientations == nil {
l.Orientations = make(layerGroup, 0)
}
if l.Shadows == nil {
l.Shadows = make(layerGroup, 0)
}
if l.Substitutions == nil {
l.Substitutions = make(layerGroup, 0)
}
}
// removes nil layers from all layer groups
func (l *ds1Layers) cull() {
l.cullNilLayers(floorLayerGroup)
l.cullNilLayers(wallLayerGroup)
l.cullNilLayers(orientationLayerGroup)
l.cullNilLayers(shadowLayerGroup)
l.cullNilLayers(substitutionLayerGroup)
}
// removes nil layers of given layer group type
func (l *ds1Layers) cullNilLayers(t layerGroupType) {
var group *layerGroup
switch t {
case floorLayerGroup:
group = &l.Floors
case wallLayerGroup:
group = &l.Walls
case orientationLayerGroup:
group = &l.Orientations
case shadowLayerGroup:
group = &l.Shadows
case substitutionLayerGroup:
group = &l.Substitutions
default:
return
}
// from last to first layer, remove first encountered nil layer and restart the culling procedure.
// exit culling procedure when no nil layers are found in entire group.
culling:
for {
for idx := len(*group) - 1; idx > 0; idx-- {
if (*group)[idx] == nil {
*group = (*group)[:idx]
continue culling
}
}
break culling // encountered no new nil layers
}
}
func (l *ds1Layers) Size() (w, h int) {
l.ensureInit()
l.cull()
return l.width, l.height
}
func (l *ds1Layers) SetSize(w, h int) {
l.width, l.height = w, h
l.enforceSize(floorLayerGroup)
l.enforceSize(wallLayerGroup)
l.enforceSize(orientationLayerGroup)
l.enforceSize(shadowLayerGroup)
l.enforceSize(substitutionLayerGroup)
}
func (l *ds1Layers) enforceSize(t layerGroupType) {
l.ensureInit()
l.cull()
var group *layerGroup
switch t {
case floorLayerGroup:
group = &l.Floors
case wallLayerGroup:
group = &l.Walls
case orientationLayerGroup:
group = &l.Orientations
case shadowLayerGroup:
group = &l.Shadows
case substitutionLayerGroup:
group = &l.Substitutions
default:
return
}
for idx := range *group {
(*group)[idx].SetSize(l.width, l.height)
}
}
func (l *ds1Layers) Width() int {
w, _ := l.Size()
return w
}
func (l *ds1Layers) SetWidth(w int) {
l.SetSize(w, l.height)
}
func (l *ds1Layers) Height() int {
_, h := l.Size()
return h
}
func (l *ds1Layers) SetHeight(h int) {
l.SetSize(l.width, h)
}
// generic push func for all layer types
func (l *ds1Layers) push(t layerGroupType, layer *layer) {
l.ensureInit()
l.cull()
var group *layerGroup
var max int
switch t {
case floorLayerGroup:
group = &l.Floors
max = maxFloorLayers
case wallLayerGroup:
group = &l.Walls
max = maxWallLayers
case orientationLayerGroup:
group = &l.Orientations
max = maxOrientationLayers
case shadowLayerGroup:
group = &l.Shadows
max = maxShadowLayers
case substitutionLayerGroup:
group = &l.Substitutions
max = maxSubstitutionLayers
default:
return
}
if len(*group) < max {
*group = append(*group, layer)
}
}
// generic pop func for all layer types
func (l *ds1Layers) pop(t layerGroupType) *layer {
l.ensureInit()
l.cull()
var group *layerGroup
var theLayer *layer
switch t {
case floorLayerGroup:
group = &l.Floors
case wallLayerGroup:
group = &l.Walls
case orientationLayerGroup:
group = &l.Orientations
case shadowLayerGroup:
group = &l.Shadows
case substitutionLayerGroup:
group = &l.Substitutions
default:
return nil
}
// remove last layer of slice and return it
if len(*group) > 0 {
lastIdx := len(*group) - 1
theLayer = (*group)[lastIdx]
*group = (*group)[:lastIdx]
return theLayer
}
return nil
}
func (l *ds1Layers) get(t layerGroupType, idx int) *layer {
l.ensureInit()
l.cull()
var group *layerGroup
switch t {
case floorLayerGroup:
group = &l.Floors
case wallLayerGroup:
group = &l.Walls
case orientationLayerGroup:
group = &l.Orientations
case shadowLayerGroup:
group = &l.Shadows
case substitutionLayerGroup:
group = &l.Substitutions
default:
return nil
}
if idx >= len(*group) || idx < 0 {
return nil
}
return (*group)[idx]
}
func (l *ds1Layers) insert(t layerGroupType, idx int, newLayer *layer) {
l.ensureInit()
l.cull()
if newLayer == nil {
return
}
var group layerGroup
switch t {
case floorLayerGroup:
group = l.Floors
case wallLayerGroup:
group = l.Walls
case orientationLayerGroup:
group = l.Orientations
case shadowLayerGroup:
group = l.Shadows
case substitutionLayerGroup:
group = l.Substitutions
default:
return
}
if len(group) == 0 {
group = append(group, newLayer) // nolint:staticcheck // we possibly use group later
return
}
if idx > len(group)-1 {
idx = len(group) - 1
}
// example:
// suppose
// idx=1
// newLayer=c
// existing layerGroup is [a, b]
group = append(group, group[idx:]...) // [a, b] becomes [a, b, b]
group[idx] = newLayer // [a, b, b] becomes [a, c, b]
}
func (l *ds1Layers) delete(t layerGroupType, idx int) {
l.ensureInit()
l.cull()
var group layerGroup
switch t {
case floorLayerGroup:
group = l.Floors
case wallLayerGroup:
group = l.Walls
case orientationLayerGroup:
group = l.Orientations
case shadowLayerGroup:
group = l.Shadows
case substitutionLayerGroup:
group = l.Substitutions
default:
return
}
if idx >= len(group) || idx < 0 {
return
}
group[idx] = nil
l.cull()
}
func (l *ds1Layers) GetFloor(idx int) *layer {
return l.get(floorLayerGroup, idx)
}
func (l *ds1Layers) PushFloor(floor *layer) *ds1Layers {
l.push(floorLayerGroup, floor)
return l
}
func (l *ds1Layers) PopFloor() *layer {
return l.pop(floorLayerGroup)
}
func (l *ds1Layers) InsertFloor(idx int, newFloor *layer) {
l.insert(floorLayerGroup, idx, newFloor)
}
func (l *ds1Layers) DeleteFloor(idx int) {
l.delete(floorLayerGroup, idx)
}
func (l *ds1Layers) GetWall(idx int) *layer {
return l.get(wallLayerGroup, idx)
}
func (l *ds1Layers) PushWall(wall *layer) *ds1Layers {
l.push(wallLayerGroup, wall)
return l
}
func (l *ds1Layers) PopWall() *layer {
return l.pop(wallLayerGroup)
}
func (l *ds1Layers) InsertWall(idx int, newWall *layer) {
l.insert(wallLayerGroup, idx, newWall)
}
func (l *ds1Layers) DeleteWall(idx int) {
l.delete(wallLayerGroup, idx)
}
func (l *ds1Layers) GetOrientation(idx int) *layer {
return l.get(orientationLayerGroup, idx)
}
func (l *ds1Layers) PushOrientation(orientation *layer) *ds1Layers {
l.push(orientationLayerGroup, orientation)
return l
}
func (l *ds1Layers) PopOrientation() *layer {
return l.pop(orientationLayerGroup)
}
func (l *ds1Layers) InsertOrientation(idx int, newOrientation *layer) {
l.insert(orientationLayerGroup, idx, newOrientation)
}
func (l *ds1Layers) DeleteOrientation(idx int) {
l.delete(orientationLayerGroup, idx)
}
func (l *ds1Layers) GetShadow(idx int) *layer {
return l.get(shadowLayerGroup, idx)
}
func (l *ds1Layers) PushShadow(shadow *layer) *ds1Layers {
l.push(shadowLayerGroup, shadow)
return l
}
func (l *ds1Layers) PopShadow() *layer {
return l.pop(shadowLayerGroup)
}
func (l *ds1Layers) InsertShadow(idx int, newShadow *layer) {
l.insert(shadowLayerGroup, idx, newShadow)
}
func (l *ds1Layers) DeleteShadow(idx int) {
l.delete(shadowLayerGroup, idx)
}
func (l *ds1Layers) GetSubstitution(idx int) *layer {
return l.get(substitutionLayerGroup, idx)
}
func (l *ds1Layers) PushSubstitution(sub *layer) *ds1Layers {
l.push(substitutionLayerGroup, sub)
return l
}
func (l *ds1Layers) PopSubstitution() *layer {
return l.pop(substitutionLayerGroup)
}
func (l *ds1Layers) InsertSubstitution(idx int, newSubstitution *layer) {
l.insert(shadowLayerGroup, idx, newSubstitution)
}
func (l *ds1Layers) DeleteSubstitution(idx int) {
l.delete(shadowLayerGroup, idx)
}