Files
questshock/modding/hacked/editor/external/Import.go
T

118 lines
3.7 KiB
Go

package external
import (
"image"
"image/color"
"math"
"os"
"github.com/inkyblackness/hacked/ss1/content/audio"
"github.com/inkyblackness/hacked/ss1/content/audio/wav"
"github.com/inkyblackness/hacked/ss1/content/bitmap"
"github.com/inkyblackness/hacked/ui/gui"
)
// Import starts an import dialog series, calling the given callback with a file name.
func Import(machine gui.ModalStateMachine, info string, types []TypeInfo, callback func(string), lastFailed bool) {
machine.SetState(&importStartState{
machine: machine,
callback: callback,
info: info,
typeInfo: types,
withError: lastFailed,
})
}
// ImportAudio is a helper to handle audio file import. The callback is called with the loaded audio.
func ImportAudio(machine gui.ModalStateMachine, callback func(l8 audio.L8)) {
info := "File must be a WAV file, 22050 Hz, 8-bit or 16-bit, uncompressed."
types := []TypeInfo{{Title: "Audio files (*.wav)", Extensions: []string{"wav"}}}
var fileHandler func(string)
fileHandler = func(filename string) {
reader, err := os.Open(filename)
if err != nil {
Import(machine, info, types, fileHandler, true)
return
}
defer func() { _ = reader.Close() }()
sound, err := wav.Load(reader)
if err != nil {
Import(machine, info, types, fileHandler, true)
return
}
callback(sound)
}
Import(machine, info, types, fileHandler, false)
}
// ImportImage is a helper to handle image file import. The callback is called with the loaded image.
func ImportImage(machine gui.ModalStateMachine, paletteRetriever func() (bitmap.Palette, error), callback func(bitmap.Bitmap)) {
info := "File should be either a BMP, GIF, or a PNG file.\nPaletted images matching game palette are taken 1:1,\nothers are mapped closest fitting."
types := []TypeInfo{{Title: "Image files (*.bmp, *.gif, *.png)", Extensions: []string{"bmp", "gif", "png"}}}
var fileHandler func(string)
fileHandler = func(filename string) {
reader, err := os.Open(filename)
if err != nil {
Import(machine, "Could not open file.\n"+info, types, fileHandler, true)
return
}
defer func() { _ = reader.Close() }()
img, _, err := image.Decode(reader)
if err != nil {
Import(machine, "File not recognized as image.\n"+info, types, fileHandler, true)
return
}
var bmp bitmap.Bitmap
importMapped := true
rawPalette, err := paletteRetriever()
if err != nil {
Import(machine, "Can not import image without having a palette loaded.\n"+info, types, fileHandler, true)
return
}
if palettedImg, isPaletted := img.(image.PalettedImage); isPaletted {
imgPalette, hasPalette := palettedImg.ColorModel().(color.Palette)
if hasPalette && paletteMatches(imgPalette, rawPalette.ColorPalette(false)) {
bounds := img.Bounds()
bmp.Header.Width = int16(math.Max(0, math.Min(float64(bounds.Dx()), math.MaxInt16)))
bmp.Header.Height = int16(math.Max(0, math.Min(float64(bounds.Dy()), math.MaxInt16)))
bmp.Pixels = make([]byte, int(bmp.Header.Width)*int(bmp.Header.Height))
for row := 0; row < int(bmp.Header.Height); row++ {
for column := 0; column < int(bmp.Header.Width); column++ {
bmp.Pixels[row*int(bmp.Header.Width)+column] = palettedImg.ColorIndexAt(column, row)
}
}
importMapped = false
}
}
if importMapped {
bitmapper := bitmap.NewBitmapper(&rawPalette)
bmp = bitmapper.Map(img)
}
callback(bmp)
}
Import(machine, info, types, fileHandler, false)
}
func paletteMatches(imgPalette color.Palette, rawPalette color.Palette) bool {
if len(imgPalette) > len(rawPalette) {
return false
}
for index, clr := range imgPalette {
imgR, imgG, imgB, _ := clr.RGBA()
rawR, rawG, rawB, _ := rawPalette[index].RGBA()
if (imgR != rawR) || (imgG != rawG) || (imgB != rawB) {
return false
}
}
return true
}