Moving some directories

This commit is contained in:
ml
2026-09-26 15:20:07 +02:00
parent e410d82680
commit c0952898ae
706 changed files with 0 additions and 0 deletions
@@ -0,0 +1,551 @@
package levels
import (
"fmt"
"github.com/inkyblackness/imgui-go/v3"
"github.com/inkyblackness/hacked/editor/graphics"
"github.com/inkyblackness/hacked/editor/render"
"github.com/inkyblackness/hacked/editor/values"
"github.com/inkyblackness/hacked/ss1/content/archive/level"
"github.com/inkyblackness/hacked/ss1/content/bitmap"
"github.com/inkyblackness/hacked/ss1/content/text"
"github.com/inkyblackness/hacked/ss1/edit"
"github.com/inkyblackness/hacked/ss1/edit/undoable/cmd"
"github.com/inkyblackness/hacked/ss1/resource"
"github.com/inkyblackness/hacked/ss1/world"
"github.com/inkyblackness/hacked/ss1/world/ids"
)
// TilesView is for tile properties.
type TilesView struct {
editor *edit.LevelEditorService
textCache *text.Cache
textureCache *graphics.TextureCache
guiScale float32
registry cmd.Registry
model tilesViewModel
}
// NewTilesView returns a new instance.
func NewTilesView(editor *edit.LevelEditorService,
guiScale float32, textCache *text.Cache, textureCache *graphics.TextureCache, registry cmd.Registry) *TilesView {
view := &TilesView{
editor: editor,
textCache: textCache,
textureCache: textureCache,
guiScale: guiScale,
model: freshTilesViewModel(),
registry: registry,
}
return view
}
// WindowOpen returns the flag address, to be used with the main menu.
func (view *TilesView) WindowOpen() *bool {
return &view.model.windowOpen
}
// TextureDisplay returns the current setting which textures should be displayed.
func (view TilesView) TextureDisplay() TextureDisplay {
return view.model.textureDisplay
}
// ColorDisplay returns the current setting which colors should be displayed.
func (view TilesView) ColorDisplay() ColorDisplay {
lvl := view.editor.Level()
if lvl.IsCyberspace() {
return view.model.cyberColorDisplay
}
return view.model.shadowDisplay
}
// Render renders the view.
func (view *TilesView) Render() {
if view.model.restoreFocus {
imgui.SetNextWindowFocus()
view.model.restoreFocus = false
view.model.windowOpen = true
}
if view.model.windowOpen {
lvl := view.editor.Level()
tiles := view.editor.Tiles()
readOnly := view.editor.IsReadOnly()
title := fmt.Sprintf("Level Tiles, %d selected", len(tiles))
if readOnly {
title += hintReadOnly
}
imgui.SetNextWindowSizeV(imgui.Vec2{X: 400 * view.guiScale, Y: 500 * view.guiScale}, imgui.ConditionFirstUseEver)
if imgui.BeginV(title+"###Level Tiles", view.WindowOpen(), 0) {
view.renderContent(lvl, tiles, readOnly)
}
imgui.End()
}
}
func (view *TilesView) renderContent(lvl *level.Level, tiles []*level.TileMapEntry, readOnly bool) {
isCyberspace := lvl.IsCyberspace()
tileTypeUnifier := values.NewUnifier()
floorHeightUnifier := values.NewUnifier()
ceilingHeightUnifier := values.NewUnifier()
slopeHeightUnifier := values.NewUnifier()
slopeControlUnifier := values.NewUnifier()
musicZoneUnifier := values.NewUnifier()
floorPaletteIndexUnifier := values.NewUnifier()
ceilingPaletteIndexUnifier := values.NewUnifier()
flightPullTypeUnifier := values.NewUnifier()
gameOfLightStateUnifier := values.NewUnifier()
floorTextureIndexUnifier := values.NewUnifier()
floorTextureRotationsUnifier := values.NewUnifier()
ceilingTextureIndexUnifier := values.NewUnifier()
ceilingTextureRotationsUnifier := values.NewUnifier()
wallTextureIndexUnifier := values.NewUnifier()
wallTextureOffsetUnifier := values.NewUnifier()
useAdjacentWallTextureUnifier := values.NewUnifier()
wallTexturePatternUnifier := values.NewUnifier()
floorLightUnifier := values.NewUnifier()
floorLightDeltaUnifier := values.NewUnifier()
ceilingLightUnifier := values.NewUnifier()
ceilingLightDeltaUnifier := values.NewUnifier()
deconstructedUnifier := values.NewUnifier()
perildUnifier := values.NewUnifier()
floorHazardUnifier := values.NewUnifier()
ceilingHazardUnifier := values.NewUnifier()
for _, tile := range tiles {
tileTypeUnifier.Add(tile.Type)
floorHeightUnifier.Add(tile.Floor.AbsoluteHeight())
ceilingHeightUnifier.Add(tile.Ceiling.AbsoluteHeight())
slopeHeightUnifier.Add(tile.SlopeHeight)
slopeControlUnifier.Add(tile.Flags.SlopeControl())
musicZoneUnifier.Add(tile.Flags.MusicZone())
perildUnifier.Add(tile.Flags.Peril())
if isCyberspace {
floorPaletteIndexUnifier.Add(tile.TextureInfo.FloorPaletteIndex())
ceilingPaletteIndexUnifier.Add(tile.TextureInfo.CeilingPaletteIndex())
flightPullTypeUnifier.Add(tile.Flags.ForCyberspace().FlightPull())
gameOfLightStateUnifier.Add(tile.Flags.ForCyberspace().GameOfLifeState())
} else {
flags := tile.Flags.ForRealWorld()
floorTextureIndexUnifier.Add(int(tile.TextureInfo.FloorTextureIndex()))
floorTextureRotationsUnifier.Add(tile.Floor.TextureRotations())
ceilingTextureIndexUnifier.Add(int(tile.TextureInfo.CeilingTextureIndex()))
ceilingTextureRotationsUnifier.Add(tile.Ceiling.TextureRotations())
wallTextureIndexUnifier.Add(int(tile.TextureInfo.WallTextureIndex()))
wallTextureOffsetUnifier.Add(flags.WallTextureOffset())
useAdjacentWallTextureUnifier.Add(flags.UseAdjacentWallTexture())
wallTexturePatternUnifier.Add(flags.WallTexturePattern())
floorLightUnifier.Add(level.GradesOfShadow - 1 - flags.FloorShadow())
floorLightDeltaUnifier.Add(tile.LightDelta.OfFloor())
ceilingLightUnifier.Add(level.GradesOfShadow - 1 - flags.CeilingShadow())
ceilingLightDeltaUnifier.Add(tile.LightDelta.OfCeiling())
deconstructedUnifier.Add(flags.Deconstructed())
floorHazardUnifier.Add(tile.Floor.HasHazard())
ceilingHazardUnifier.Add(tile.Ceiling.HasHazard())
}
}
imgui.PushItemWidth(-250 * view.guiScale)
_, _, levelHeight := lvl.Size()
tileHeightFormatter := tileHeightFormatterFor(levelHeight)
tileTypes := level.TileTypes()
values.RenderUnifiedCombo(readOnly, "Tile Type", tileTypeUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileType)) },
func(value int) string { return tileTypes[value].String() },
len(tileTypes),
func(newValue int) { view.changeTiles(setTileTypeTo(level.TileType(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Floor Height", floorHeightUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileHeightUnit)) },
tileHeightFormatter,
0, int(level.TileHeightUnitMax)-1,
func(newValue int) { view.changeTiles(setFloorHeightTo(level.TileHeightUnit(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Height (abs)", ceilingHeightUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileHeightUnit)) },
tileHeightFormatter,
1, int(level.TileHeightUnitMax),
func(newValue int) { view.changeTiles(setCeilingHeightTo(level.TileHeightUnit(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Slope Height", slopeHeightUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileHeightUnit)) },
tileHeightFormatter,
0, int(level.TileHeightUnitMax)-1,
func(newValue int) { view.changeTiles(setSlopeHeightTo(level.TileHeightUnit(newValue))) })
slopeControls := level.TileSlopeControls()
values.RenderUnifiedCombo(readOnly, "Slope Control", slopeControlUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileSlopeControl)) },
func(value int) string { return slopeControls[value].String() },
len(slopeControls),
func(newValue int) { view.changeTiles(setSlopeControlTo(slopeControls[newValue])) })
musicZones := level.TileMusicZones()
values.RenderUnifiedCombo(readOnly, "Music Zone", musicZoneUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileMusicZone)) },
func(value int) string { return musicZones[value].String() },
len(musicZones),
func(newValue int) { view.changeTiles(setMusicZoneTo(musicZones[newValue])) })
values.RenderUnifiedCheckboxCombo(readOnly, "Music Peril", perildUnifier,
func(newValue bool) { view.changeTiles(setPerilTo(newValue)) })
imgui.Separator()
if isCyberspace {
if imgui.BeginCombo("Color View", view.model.cyberColorDisplay.String()) {
displays := ColorDisplays()
for _, display := range displays {
displayString := display.String()
if imgui.SelectableV(displayString, display == view.model.cyberColorDisplay, 0, imgui.Vec2{}) {
view.model.cyberColorDisplay = display
}
}
imgui.EndCombo()
}
values.RenderUnifiedSliderInt(readOnly, "Floor Color", floorPaletteIndexUnifier,
func(u values.Unifier) int { return int(u.Unified().(byte)) },
func(value int) string { return "%d" },
0, bitmap.PaletteSize-1,
func(newValue int) { view.changeTiles(setFloorPaletteIndexTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Color", ceilingPaletteIndexUnifier,
func(u values.Unifier) int { return int(u.Unified().(byte)) },
func(value int) string { return "%d" },
0, bitmap.PaletteSize-1,
func(newValue int) { view.changeTiles(setCeilingPaletteIndexTo(newValue)) })
imgui.Separator()
flightPulls := level.CyberspaceFlightPulls()
values.RenderUnifiedCombo(readOnly, "Flight Pull Type", flightPullTypeUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.CyberspaceFlightPull)) },
func(value int) string { return flightPulls[value].String() },
len(flightPulls),
func(newValue int) { view.changeTiles(setFlightPullTypeTo(flightPulls[newValue])) })
values.RenderUnifiedSliderInt(readOnly, "Game Of Life State", gameOfLightStateUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, 3,
func(newValue int) { view.changeTiles(setGameOfLightStateTo(newValue)) })
} else {
atlas := lvl.TextureAtlas()
if imgui.BeginCombo("Texture View", view.model.textureDisplay.String()) {
displays := TextureDisplays()
for _, display := range displays {
displayString := display.String()
if imgui.SelectableV(displayString, display == view.model.textureDisplay, 0, imgui.Vec2{}) {
view.model.textureDisplay = display
}
}
imgui.EndCombo()
}
values.RenderUnifiedSliderInt(readOnly, "Floor Texture (atlas index)", floorTextureIndexUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.FloorCeilingTextureLimit-1,
func(newValue int) { view.changeTiles(setFloorTextureIndexTo(level.AtlasIndex(newValue))) })
view.renderTextureSelector(readOnly, "Floor Texture", floorTextureIndexUnifier, atlas, 0, level.FloorCeilingTextureLimit-1,
func(newValue int) { view.changeTiles(setFloorTextureIndexTo(level.AtlasIndex(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Floor Texture Rotations", floorTextureRotationsUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, 3,
func(newValue int) { view.changeTiles(setFloorTextureRotationsTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Texture (atlas index)", ceilingTextureIndexUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.FloorCeilingTextureLimit-1,
func(newValue int) { view.changeTiles(setCeilingTextureIndexTo(level.AtlasIndex(newValue))) })
view.renderTextureSelector(readOnly, "Ceiling Texture", ceilingTextureIndexUnifier, atlas, 0, level.FloorCeilingTextureLimit-1,
func(newValue int) { view.changeTiles(setCeilingTextureIndexTo(level.AtlasIndex(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Texture Rotations", ceilingTextureRotationsUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, 3,
func(newValue int) { view.changeTiles(setCeilingTextureRotationsTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Wall Texture (atlas index)", wallTextureIndexUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, len(atlas)-1,
func(newValue int) { view.changeTiles(setWallTextureIndexTo(level.AtlasIndex(newValue))) })
view.renderTextureSelector(readOnly, "Wall Texture", wallTextureIndexUnifier, atlas, 0, len(atlas)-1,
func(newValue int) { view.changeTiles(setWallTextureIndexTo(level.AtlasIndex(newValue))) })
values.RenderUnifiedSliderInt(readOnly, "Wall Texture Offset", wallTextureOffsetUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.TileHeightUnit)) },
tileHeightFormatter,
0, int(level.TileHeightUnitMax)-1,
func(newValue int) { view.changeTiles(setWallTextureOffsetTo(level.TileHeightUnit(newValue))) })
values.RenderUnifiedCheckboxCombo(readOnly, "Use Adjacent Wall Texture", useAdjacentWallTextureUnifier,
func(newValue bool) { view.changeTiles(setUseAdjacentWallTextureTo(newValue)) })
wallTexturePatterns := level.WallTexturePatterns()
values.RenderUnifiedCombo(readOnly, "Wall Texture Pattern", wallTexturePatternUnifier,
func(u values.Unifier) int { return int(u.Unified().(level.WallTexturePattern)) },
func(value int) string { return wallTexturePatterns[value].String() },
len(wallTexturePatterns),
func(newValue int) { view.changeTiles(setWallTexturePatternTo(wallTexturePatterns[newValue])) })
imgui.Separator()
if imgui.BeginCombo("Shadow View", view.model.shadowDisplay.String()) {
displays := ColorDisplays()
for _, display := range displays {
displayString := display.String()
if imgui.SelectableV(displayString, display == view.model.shadowDisplay, 0, imgui.Vec2{}) {
view.model.shadowDisplay = display
}
}
imgui.EndCombo()
}
values.RenderUnifiedSliderInt(readOnly, "Floor Light", floorLightUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.GradesOfShadow-1,
func(newValue int) { view.changeTiles(setFloorLightTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Floor Light Delta", floorLightDeltaUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.GradesOfShadow-1,
func(newValue int) { view.changeTiles(setFloorLightDeltaTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Light", ceilingLightUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.GradesOfShadow-1,
func(newValue int) { view.changeTiles(setCeilingLightTo(newValue)) })
values.RenderUnifiedSliderInt(readOnly, "Ceiling Light Delta", ceilingLightDeltaUnifier,
func(u values.Unifier) int { return u.Unified().(int) },
func(value int) string { return "%d" },
0, level.GradesOfShadow-1,
func(newValue int) { view.changeTiles(setCeilingLightDeltaTo(newValue)) })
imgui.Separator()
values.RenderUnifiedCheckboxCombo(readOnly, "Deconstructed", deconstructedUnifier,
func(newValue bool) { view.changeTiles(setDeconstructedTo(newValue)) })
values.RenderUnifiedCheckboxCombo(readOnly, "Floor Hazard", floorHazardUnifier,
func(newValue bool) { view.changeTiles(setFloorHazardTo(newValue)) })
values.RenderUnifiedCheckboxCombo(readOnly, "Ceiling Hazard", ceilingHazardUnifier,
func(newValue bool) { view.changeTiles(setCeilingHazardTo(newValue)) })
}
imgui.PopItemWidth()
}
func (view *TilesView) renderTextureSelector(readOnly bool, label string, unifier values.Unifier,
atlas level.TextureAtlas, minIndex, maxIndex int, changeHandler func(int)) {
selectedIndex := -1
if unifier.IsUnique() {
selectedIndex = unifier.Unified().(int)
}
count := maxIndex - minIndex + 1
if count > len(atlas) {
count = len(atlas)
}
render.TextureSelector(label, -1, view.guiScale, count, selectedIndex-minIndex,
view.textureCache,
func(index int) resource.Key {
return resource.KeyOf(ids.LargeTextures.Plus(int(atlas[minIndex+index])), resource.LangAny, 0)
},
func(index int) string { return view.textureName(int(atlas[minIndex+index])) },
func(index int) {
if !readOnly {
changeHandler(index)
}
})
}
func (view *TilesView) textureName(index int) string {
key := resource.KeyOf(ids.TextureNames, resource.LangDefault, index)
name, err := view.textCache.Text(key)
suffix := ""
if err == nil {
suffix = ": " + name
}
return fmt.Sprintf("%3d", index) + suffix
}
func setTileTypeTo(tileType level.TileType) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Type = tileType
}
}
func setFloorHeightTo(height level.TileHeightUnit) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Floor = tile.Floor.WithAbsoluteHeight(height)
}
}
func setCeilingHeightTo(height level.TileHeightUnit) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Ceiling = tile.Ceiling.WithAbsoluteHeight(height)
}
}
func setSlopeHeightTo(height level.TileHeightUnit) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.SlopeHeight = height
}
}
func setSlopeControlTo(value level.TileSlopeControl) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.WithSlopeControl(value)
}
}
func setPerilTo(value bool) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.WithPeril(value)
}
}
func setMusicZoneTo(value level.TileMusicZone) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.WithMusicZone(value)
}
}
func setFloorTextureIndexTo(value level.AtlasIndex) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.TextureInfo = tile.TextureInfo.WithFloorTextureIndex(value)
}
}
func setFloorTextureRotationsTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Floor = tile.Floor.WithTextureRotations(value)
}
}
func setCeilingTextureIndexTo(value level.AtlasIndex) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.TextureInfo = tile.TextureInfo.WithCeilingTextureIndex(value)
}
}
func setCeilingTextureRotationsTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Ceiling = tile.Ceiling.WithTextureRotations(value)
}
}
func setWallTextureIndexTo(value level.AtlasIndex) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.TextureInfo = tile.TextureInfo.WithWallTextureIndex(value)
}
}
func setWallTextureOffsetTo(value level.TileHeightUnit) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithWallTextureOffset(value).AsTileFlag()
}
}
func setUseAdjacentWallTextureTo(value bool) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithUseAdjacentWallTexture(value).AsTileFlag()
}
}
func setWallTexturePatternTo(value level.WallTexturePattern) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithWallTexturePattern(value).AsTileFlag()
}
}
func setFloorLightTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithFloorShadow(level.GradesOfShadow - 1 - value).AsTileFlag()
}
}
func setFloorLightDeltaTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.LightDelta = tile.LightDelta.WithFloor(value)
}
}
func setCeilingLightTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithCeilingShadow(level.GradesOfShadow - 1 - value).AsTileFlag()
}
}
func setCeilingLightDeltaTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.LightDelta = tile.LightDelta.WithCeiling(value)
}
}
func setDeconstructedTo(value bool) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForRealWorld().WithDeconstructed(value).AsTileFlag()
}
}
func setFloorHazardTo(value bool) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Floor = tile.Floor.WithHazard(value)
}
}
func setCeilingHazardTo(value bool) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Ceiling = tile.Ceiling.WithHazard(value)
}
}
func setFloorPaletteIndexTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.TextureInfo = tile.TextureInfo.WithFloorPaletteIndex(byte(value))
}
}
func setCeilingPaletteIndexTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.TextureInfo = tile.TextureInfo.WithCeilingPaletteIndex(byte(value))
}
}
func setFlightPullTypeTo(value level.CyberspaceFlightPull) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForCyberspace().WithFlightPull(value).AsTileFlag()
}
}
func setGameOfLightStateTo(value int) tileMapEntryModifier {
return func(tile *level.TileMapEntry) {
tile.Flags = tile.Flags.ForCyberspace().WithGameOfLifeState(value).AsTileFlag()
}
}
type tileMapEntryModifier func(*level.TileMapEntry)
func (view *TilesView) changeTiles(modifier tileMapEntryModifier) {
err := view.registry.Register(cmd.Named("ChangeTiles"),
cmd.Forward(view.restoreFocusTask()),
cmd.Nested(func() error { return view.editor.ChangeTiles(modifier) }),
cmd.Reverse(view.restoreFocusTask()))
if err != nil {
panic(err)
}
}
func (view *TilesView) restoreFocusTask() cmd.Task {
return func(modder world.Modder) error {
view.model.restoreFocus = true
return nil
}
}