99 lines
2.2 KiB
Go
99 lines
2.2 KiB
Go
package bitmap
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/inkyblackness/hacked/ss1"
|
|
"github.com/inkyblackness/hacked/ss1/resource"
|
|
"github.com/inkyblackness/hacked/ss1/serial"
|
|
)
|
|
|
|
const (
|
|
animationEndTag = 0x0C
|
|
animationEndTagData = 0x01
|
|
|
|
animationEntryTag = 0x04
|
|
|
|
errEndTagDataWrong ss1.StringError = "end tag data wrong"
|
|
)
|
|
|
|
type unknownEntryTagError struct {
|
|
tag byte
|
|
}
|
|
|
|
func (err unknownEntryTagError) Error() string {
|
|
return fmt.Sprintf("unknown entry tag 0x%02X", int(err.tag))
|
|
}
|
|
|
|
// Animation describes a sequence of bitmaps to form a small movie.
|
|
type Animation struct {
|
|
Width int16
|
|
Height int16
|
|
ResourceID resource.ID
|
|
IntroFlag uint16
|
|
Entries []AnimationEntry
|
|
}
|
|
|
|
// AnimationEntry describes one part of an animation with common frame time.
|
|
type AnimationEntry struct {
|
|
FirstFrame byte
|
|
LastFrame byte
|
|
FrameTime int16
|
|
}
|
|
|
|
// ReadAnimation extracts an animation from a serialized stream.
|
|
func ReadAnimation(reader io.Reader) (anim Animation, err error) {
|
|
decoder := serial.NewDecoder(reader)
|
|
codeAnimationBase(decoder, &anim)
|
|
done := false
|
|
err = decoder.FirstError()
|
|
for !done && (err == nil) {
|
|
var tag byte
|
|
decoder.Code(&tag)
|
|
err = decoder.FirstError()
|
|
switch tag {
|
|
case animationEntryTag:
|
|
var entry AnimationEntry
|
|
decoder.Code(&entry)
|
|
anim.Entries = append(anim.Entries, entry)
|
|
err = decoder.FirstError()
|
|
case animationEndTag:
|
|
var endTagData byte
|
|
decoder.Code(&endTagData)
|
|
if endTagData != animationEndTagData {
|
|
err = errEndTagDataWrong
|
|
}
|
|
done = true
|
|
default:
|
|
if err == nil {
|
|
err = unknownEntryTagError{tag: tag}
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// WriteAnimation serializes an animation to a writer.
|
|
func WriteAnimation(writer io.Writer, anim Animation) error {
|
|
encoder := serial.NewEncoder(writer)
|
|
codeAnimationBase(encoder, &anim)
|
|
for _, entry := range anim.Entries {
|
|
encoder.Code([]byte{animationEntryTag})
|
|
encoder.Code(&entry) // nolint: scopelint
|
|
}
|
|
encoder.Code([]byte{animationEndTag, animationEndTagData})
|
|
|
|
return encoder.FirstError()
|
|
}
|
|
|
|
func codeAnimationBase(coder serial.Coder, anim *Animation) {
|
|
coder.Code(&anim.Width)
|
|
coder.Code(&anim.Height)
|
|
coder.Code(&anim.ResourceID)
|
|
var unknown [6]byte
|
|
coder.Code(&unknown)
|
|
coder.Code(&anim.IntroFlag)
|
|
}
|