This commit is contained in:
elee 2022-03-25 02:33:23 -05:00
parent 47850d7b13
commit 4057b3c3c6
6 changed files with 135 additions and 44 deletions

View File

@ -13,7 +13,7 @@ type Frame struct {
CoordinateCount uint32 CoordinateCount uint32
Coordinates [][2]uint32 Coordinates [][2]uint32
Unknown1 string Unknown1 string
Sound_effect string SoundEffect string
Unknown2 string Unknown2 string
Camp CampSection Camp CampSection
} }
@ -23,8 +23,17 @@ type CampSection struct {
Extra string Extra string
} }
type Plane struct {
BitmapId uint32
PlaneX int32
PlaneY int32
Opacity uint32
Blend BlendMode
FlagParam uint32
RenderFlag uint32
}
type Animation struct { type Animation struct {
Title string Title [32]byte
// std::vector<uint32> frame_offsets // std::vector<uint32> frame_offsets
FrameCount uint32 FrameCount uint32
@ -32,9 +41,15 @@ type Animation struct {
} }
func (a *Animation) Decode(rd *bufio.Reader, version int) error { func (a *Animation) Decode(rd *bufio.Reader, version int) error {
if err := binary.Read(rd, end, a.Title[:]); err != nil {
return err
}
if err := binary.Read(rd, end, &a.FrameCount); err != nil { if err := binary.Read(rd, end, &a.FrameCount); err != nil {
return err return err
} }
if _, err := rd.Discard(4 * int(a.FrameCount)); err != nil {
return err
}
a.Frames = make([]*Frame, int(a.FrameCount)) a.Frames = make([]*Frame, int(a.FrameCount))
for i := range a.Frames { for i := range a.Frames {
cf := &Frame{} cf := &Frame{}
@ -42,29 +57,31 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error {
if err := binary.Read(rd, end, &cf.Duration); err != nil { if err := binary.Read(rd, end, &cf.Duration); err != nil {
return err return err
} }
if err := binary.Read(rd, end, &cf.PlaneCount); err != nil { if err := binary.Read(rd, end, &cf.PlaneCount); err != nil {
return err return err
} }
cf.Planes = make([]*Plane, int(cf.PlaneCount)) cf.Planes = make([]*Plane, int(cf.PlaneCount))
for i := range cf.Planes { for i := range cf.Planes {
cp := &Plane{} cp := &Plane{}
cf.Planes[i] = cp cf.Planes[i] = cp
if err := binary.Read(rd, end, &cp.BitmapId); err != nil {
return err
}
if err := binary.Read(rd, end, &cp.PlaneX); err != nil { if err := binary.Read(rd, end, &cp.PlaneX); err != nil {
return err return err
} }
if err := binary.Read(rd, end, &cp.PlaneY); err != nil { if err := binary.Read(rd, end, &cp.PlaneY); err != nil {
return err return err
} }
if err := binary.Read(rd, end, &cp.Opacity); err != nil { if err := binary.Read(rd, end, &cp.Opacity); err != nil {
return err return err
} }
if err := binary.Read(rd, end, &cp.RenderFlag); err != nil { if err := binary.Read(rd, end, &cp.RenderFlag); err != nil {
return err return err
} }
if err := binary.Read(rd, end, &cp.Blend); err != nil {
return err
}
if err := binary.Read(rd, end, &cp.FlagParam); err != nil { if err := binary.Read(rd, end, &cp.FlagParam); err != nil {
return err return err
} }
@ -75,7 +92,10 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error {
} }
cf.Coordinates = make([][2]uint32, cf.CoordinateCount) cf.Coordinates = make([][2]uint32, cf.CoordinateCount)
for i := range cf.Coordinates { for i := range cf.Coordinates {
if err := binary.Read(rd, end, cf.Coordinates[i]); err != nil { if err := binary.Read(rd, end, &cf.Coordinates[i][0]); err != nil {
return err
}
if err := binary.Read(rd, end, &cf.Coordinates[i][1]); err != nil {
return err return err
} }
} }
@ -112,9 +132,9 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error {
if err := binary.Read(rd, end, &cast); err != nil { if err := binary.Read(rd, end, &cast); err != nil {
return err return err
} }
if version > 303 && (cast > 1) { if version >= 303 && (cast > 0) {
cf.Camp = CampSection{} cf.Camp = CampSection{}
if err := binary.Read(rd, end, &cf.Camp.Params); err != nil { if err := binary.Read(rd, end, cf.Camp.Params[:]); err != nil {
return err return err
} }
sz := int(cf.Camp.Params[1]) * int(cf.Camp.Params[2]) sz := int(cf.Camp.Params[1]) * int(cf.Camp.Params[2])
@ -122,17 +142,10 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error {
if _, err := io.ReadFull(rd, cf.Camp.Array); err != nil { if _, err := io.ReadFull(rd, cf.Camp.Array); err != nil {
return err return err
} }
if _, err := rd.Discard(20); err != nil {
return err
}
} }
} }
return nil return nil
} }
type Plane struct {
Bitmap_id uint32
PlaneX int32
PlaneY int32
Opacity uint32
Blend BlendMode
FlagParam uint32
RenderFlag uint32
}

View File

@ -1,15 +1,22 @@
package nori package nori
import "gitlab.com/gfxlabs/gfximg/apng" import (
"fmt"
"image"
"image/draw"
func (n *Nori) ExportAnimation() *apng.APNG { "git.tuxpa.in/a/zlog/log"
"gitlab.com/gfxlabs/gfximg/apng"
)
func (n *Nori) ShowAnimation() *apng.APNG {
g := n.Gawi g := n.Gawi
a := &apng.APNG{ a := &apng.APNG{
Frames: make([]apng.Frame, 0, len(g.Images)), Frames: make([]apng.Frame, 0, len(g.Images)),
} }
for i := 0; i < len(g.Images); i++ { for i := 0; i < len(g.Images); i++ {
fr := apng.Frame{ fr := apng.Frame{
Image: g.Images[i].Frame, Image: g.Images[i].Img,
DelayNumerator: uint16(g.Images[i].Delay), DelayNumerator: uint16(g.Images[i].Delay),
DelayDenominator: 1000, DelayDenominator: 1000,
} }
@ -17,3 +24,60 @@ func (n *Nori) ExportAnimation() *apng.APNG {
} }
return a return a
} }
func (n *Nori) ExportAnimation() (*apng.APNG, error) {
g := n.Gawi
a := &apng.APNG{
Frames: make([]apng.Frame, 0, len(g.Images)),
}
for i := 0; i < len(n.Animations); i++ {
for _, v := range n.Animations[i].Frames {
canvasRect := image.Rect(0, 0, 0, 0)
for _, plane := range v.Planes {
if int(plane.BitmapId) >= len(n.Gawi.Images) {
log.Printf("could not find bitmap %d, only have %d", plane.BitmapId, len(n.Gawi.Images))
}
bitmap := n.Gawi.Images[plane.BitmapId]
canvasRect = canvasRect.Union(bitmap.Img.Bounds())
}
img := image.NewRGBA64(canvasRect)
for _, plane := range v.Planes {
bitmap := n.Gawi.Images[plane.BitmapId]
transparent := false
//flipx
if plane.RenderFlag&1 != 0 {
}
//flipy
if plane.RenderFlag&2 != 0 {
}
// is transparent
if plane.RenderFlag&0x20 != 0 {
transparent = true
}
_ = transparent
switch plane.Blend {
case BlendMode_Alpha:
case BlendMode_Mul, BlendMode_Mul7:
case BlendMode_Add, BlendMode_Add8:
case BlendMode_InvertMul, BlendMode_InvertMul5:
case BlendMode_None:
break
default:
return nil, fmt.Errorf("unknown blend mode: %d", plane.Blend)
}
draw.Draw(img,
img.Rect,
bitmap.Img,
image.Point{X: int(plane.PlaneX),
Y: int(plane.PlaneY)}, draw.Over)
}
fr := apng.Frame{
Image: g.Images[i].Img,
DelayNumerator: uint16(g.Images[i].Delay),
DelayDenominator: 1000,
}
a.Frames = append(a.Frames, fr)
}
}
return a, nil
}

View File

@ -22,13 +22,12 @@ type Image struct {
Size uint32 Size uint32
Data []byte Data []byte
Frame image.Image Img image.Image
} }
func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error { func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height))) cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height)))
i.Frame = cf i.Img = cf
switch i.Bpp { switch i.Bpp {
case 8: case 8:
if palette == nil { if palette == nil {
@ -80,4 +79,3 @@ func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error {
return fmt.Errorf("unsupported bpp, %d", i.Bpp) return fmt.Errorf("unsupported bpp, %d", i.Bpp)
} }
} }

View File

@ -12,43 +12,53 @@ import (
func TestParseFile1(t *testing.T) { func TestParseFile1(t *testing.T) {
rd, err := os.OpenFile("./nori_test/test1.nri", os.O_RDONLY, 0666) rd, err := os.OpenFile("./nori_test/test1.nri", os.O_RDONLY, 0666)
if err != nil { if err != nil {
t.Fatalf("open file: %s", err) t.Errorf("open file: %s", err)
} }
nori, err := NewReader(rd).Decode() nori, err := NewReader(rd).Decode()
if err != nil { if err != nil {
t.Fatalf("decode: %s", err) t.Errorf("decode: %s", err)
}
t.Logf("\n nori: %+v", nori)
t.Logf("\n gawi: %+v", nori.Gawi)
a, err := nori.ExportAnimation()
if err != nil {
t.Errorf("export: %s", err)
} }
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
a := nori.ExportAnimation()
writeApng(a, "./nori_test/test1.apng") writeApng(a, "./nori_test/test1.apng")
} }
func TestParseFile2(t *testing.T) { func TestParseFile2(t *testing.T) {
rd, err := os.OpenFile("./nori_test/test2.nri", os.O_RDONLY, 0666) rd, err := os.OpenFile("./nori_test/test2.nri", os.O_RDONLY, 0666)
if err != nil { if err != nil {
t.Fatalf("open file: %s", err) t.Errorf("open file: %s", err)
} }
nori, err := NewReader(rd).Decode() nori, err := NewReader(rd).Decode()
if err != nil { if err != nil {
t.Fatalf("decode: %s", err) t.Errorf("decode: %s", err)
} }
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi) t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
a := nori.ExportAnimation() a, err := nori.ExportAnimation()
if err != nil {
t.Errorf("export: %s", err)
}
writeApng(a, "./nori_test/test2.apng") writeApng(a, "./nori_test/test2.apng")
} }
func TestParsePalette(t *testing.T) { func TestParsePalette(t *testing.T) {
rd, err := os.OpenFile("./nori_test/palette.nri", os.O_RDONLY, 0666) rd, err := os.OpenFile("./nori_test/palette.nri", os.O_RDONLY, 0666)
if err != nil { if err != nil {
t.Logf("open file: %s", err) t.Errorf("open file: %s", err)
t.Fail()
} }
nori, err := NewReader(rd).Decode() nori, err := NewReader(rd).Decode()
if err != nil { if err != nil {
t.Errorf("decode: %s", err) t.Errorf("decode: %s", err)
} }
t.Logf("\n nori: %+v\n gawi: %+v\n palette: %+v\n", nori, nori.Gawi, nori.Gawi.Palette) t.Logf("\n nori: %+v\n gawi: %+v\n palette: %+v\n", nori, nori.Gawi, nori.Gawi.Palette)
a := nori.ExportAnimation() a, err := nori.ExportAnimation()
if err != nil {
t.Errorf("export: %s", err)
}
writeApng(a, "./nori_test/palette.apng") writeApng(a, "./nori_test/palette.apng")
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 969 KiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

@ -26,28 +26,28 @@ func NewReader(rd io.Reader) *Reader {
func (n *Reader) Decode() (*Nori, error) { func (n *Reader) Decode() (*Nori, error) {
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil { if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
return nil, err return n.nori, err
} }
if sig, target := string(n.nori.lastSignature[:]), "NORI"; sig != target { if sig, target := string(n.nori.lastSignature[:]), "NORI"; sig != target {
return nil, fmt.Errorf("expected header %s, got %s", target, sig) return n.nori, fmt.Errorf("expected header %s, got %s", target, sig)
} }
if err := binary.Read(n, end, &n.nori.Version); err != nil { if err := binary.Read(n, end, &n.nori.Version); err != nil {
return nil, err return n.nori, err
} }
if err := binary.Read(n, end, n.nori.Params[:]); err != nil { if err := binary.Read(n, end, n.nori.Params[:]); err != nil {
return nil, err return n.nori, err
} }
if err := binary.Read(n, end, &n.nori.AnimationCount); err != nil { if err := binary.Read(n, end, &n.nori.AnimationCount); err != nil {
return nil, err return n.nori, err
} }
if err := binary.Read(n, end, &n.nori.SizeNoGawi); err != nil { if err := binary.Read(n, end, &n.nori.SizeNoGawi); err != nil {
return nil, err return n.nori, err
} }
if err := binary.Read(n, end, &n.nori.TotalSize); err != nil { if err := binary.Read(n, end, &n.nori.TotalSize); err != nil {
return nil, err return n.nori, err
} }
if err := n.decodeGawi(); err != nil { if err := n.decodeGawi(); err != nil {
return nil, err return n.nori, err
} }
return n.nori, nil return n.nori, nil
} }
@ -117,6 +117,12 @@ func (n *Reader) decodeGawi() error {
return err return err
} }
n.nori.Animations = make([]*Animation, n.nori.AnimationCount) n.nori.Animations = make([]*Animation, n.nori.AnimationCount)
for i := range n.nori.Animations {
n.nori.Animations[i] = &Animation{}
if err := n.nori.Animations[i].Decode(n.r, int(n.nori.Version)); err != nil {
return err
}
}
return nil return nil
} }