diff --git a/common/nori/animation.go b/common/nori/animation.go index 65a6422..215badc 100644 --- a/common/nori/animation.go +++ b/common/nori/animation.go @@ -13,7 +13,7 @@ type Frame struct { CoordinateCount uint32 Coordinates [][2]uint32 Unknown1 string - Sound_effect string + SoundEffect string Unknown2 string Camp CampSection } @@ -23,8 +23,17 @@ type CampSection struct { Extra string } +type Plane struct { + BitmapId uint32 + PlaneX int32 + PlaneY int32 + Opacity uint32 + Blend BlendMode + FlagParam uint32 + RenderFlag uint32 +} type Animation struct { - Title string + Title [32]byte // std::vector frame_offsets FrameCount uint32 @@ -32,9 +41,15 @@ type Animation struct { } 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 { return err } + if _, err := rd.Discard(4 * int(a.FrameCount)); err != nil { + return err + } a.Frames = make([]*Frame, int(a.FrameCount)) for i := range a.Frames { 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 { return err } - if err := binary.Read(rd, end, &cf.PlaneCount); err != nil { return err } - cf.Planes = make([]*Plane, int(cf.PlaneCount)) for i := range cf.Planes { cp := &Plane{} 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 { return err } - if err := binary.Read(rd, end, &cp.PlaneY); err != nil { return err } - if err := binary.Read(rd, end, &cp.Opacity); err != nil { return err } if err := binary.Read(rd, end, &cp.RenderFlag); err != nil { return err } + if err := binary.Read(rd, end, &cp.Blend); err != nil { + return err + } if err := binary.Read(rd, end, &cp.FlagParam); err != nil { return err } @@ -75,7 +92,10 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error { } cf.Coordinates = make([][2]uint32, cf.CoordinateCount) 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 } } @@ -112,9 +132,9 @@ func (a *Animation) Decode(rd *bufio.Reader, version int) error { if err := binary.Read(rd, end, &cast); err != nil { return err } - if version > 303 && (cast > 1) { + if version >= 303 && (cast > 0) { 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 } 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 { return err } + if _, err := rd.Discard(20); err != nil { + return err + } } } return nil } - -type Plane struct { - Bitmap_id uint32 - PlaneX int32 - PlaneY int32 - Opacity uint32 - Blend BlendMode - FlagParam uint32 - RenderFlag uint32 -} diff --git a/common/nori/export.go b/common/nori/export.go index c51fd73..8f68dcc 100644 --- a/common/nori/export.go +++ b/common/nori/export.go @@ -1,15 +1,22 @@ 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 a := &apng.APNG{ Frames: make([]apng.Frame, 0, len(g.Images)), } for i := 0; i < len(g.Images); i++ { fr := apng.Frame{ - Image: g.Images[i].Frame, + Image: g.Images[i].Img, DelayNumerator: uint16(g.Images[i].Delay), DelayDenominator: 1000, } @@ -17,3 +24,60 @@ func (n *Nori) ExportAnimation() *apng.APNG { } 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 +} diff --git a/common/nori/image.go b/common/nori/image.go index 15a81b7..c45712e 100644 --- a/common/nori/image.go +++ b/common/nori/image.go @@ -22,13 +22,12 @@ type Image struct { Size uint32 Data []byte - Frame image.Image + Img image.Image } - func (i *Image) Decode(rd *bufio.Reader, palette *PaletteSection) error { cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height))) - i.Frame = cf + i.Img = cf switch i.Bpp { case 8: 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) } } - diff --git a/common/nori/nori_test.go b/common/nori/nori_test.go index d9217d6..1b4988d 100644 --- a/common/nori/nori_test.go +++ b/common/nori/nori_test.go @@ -12,43 +12,53 @@ import ( func TestParseFile1(t *testing.T) { rd, err := os.OpenFile("./nori_test/test1.nri", os.O_RDONLY, 0666) if err != nil { - t.Fatalf("open file: %s", err) + t.Errorf("open file: %s", err) } nori, err := NewReader(rd).Decode() 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") } func TestParseFile2(t *testing.T) { rd, err := os.OpenFile("./nori_test/test2.nri", os.O_RDONLY, 0666) if err != nil { - t.Fatalf("open file: %s", err) + t.Errorf("open file: %s", err) } nori, err := NewReader(rd).Decode() if err != nil { - t.Fatalf("decode: %s", err) + t.Errorf("decode: %s", err) } 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") } func TestParsePalette(t *testing.T) { rd, err := os.OpenFile("./nori_test/palette.nri", os.O_RDONLY, 0666) if err != nil { - t.Logf("open file: %s", err) - t.Fail() + t.Errorf("open file: %s", err) } nori, err := NewReader(rd).Decode() if err != nil { t.Errorf("decode: %s", err) } 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") } diff --git a/common/nori/nori_test/palette.apng b/common/nori/nori_test/palette.apng index 1bdc8b8..34bf790 100755 Binary files a/common/nori/nori_test/palette.apng and b/common/nori/nori_test/palette.apng differ diff --git a/common/nori/reader.go b/common/nori/reader.go index eea31a1..418fe0b 100644 --- a/common/nori/reader.go +++ b/common/nori/reader.go @@ -26,28 +26,28 @@ func NewReader(rd io.Reader) *Reader { func (n *Reader) Decode() (*Nori, error) { 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 { - 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 { - return nil, err + return n.nori, err } 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 { - return nil, err + return n.nori, err } 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 { - return nil, err + return n.nori, err } if err := n.decodeGawi(); err != nil { - return nil, err + return n.nori, err } return n.nori, nil } @@ -117,6 +117,12 @@ func (n *Reader) decodeGawi() error { return err } 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 }