file reading
This commit is contained in:
commit
023563f713
|
@ -0,0 +1,10 @@
|
||||||
|
bin/
|
||||||
|
out/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.bin
|
||||||
|
|
||||||
|
*test.png
|
|
@ -0,0 +1,139 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Frame struct {
|
||||||
|
Duration uint32
|
||||||
|
PlaneCount uint32
|
||||||
|
Planes []*Plane
|
||||||
|
CoordinateCount uint32
|
||||||
|
Coordinates [][2]uint32
|
||||||
|
Unknown1 string
|
||||||
|
Sound_effect string
|
||||||
|
Unknown2 string
|
||||||
|
Camp CampSection
|
||||||
|
}
|
||||||
|
type CampSection struct {
|
||||||
|
Params [7]uint32
|
||||||
|
Array []byte
|
||||||
|
Extra string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Animation struct {
|
||||||
|
Title string
|
||||||
|
|
||||||
|
// std::vector<uint32> frame_offsets
|
||||||
|
FrameCount uint32
|
||||||
|
Frames []*Frame
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Animation) Decode(rd *bufio.Reader, version int) error {
|
||||||
|
if err := binary.Read(rd, end, &a.FrameCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
a.Frames = make([]*Frame, int(a.FrameCount))
|
||||||
|
for i := range a.Frames {
|
||||||
|
cf := &Frame{}
|
||||||
|
a.Frames[i] = cf
|
||||||
|
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.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.FlagParam); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if version != 300 {
|
||||||
|
if err := binary.Read(rd, end, &cf.CoordinateCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cf.Coordinates = make([][2]uint32, cf.CoordinateCount)
|
||||||
|
for i := range cf.Coordinates {
|
||||||
|
if err := binary.Read(rd, end, cf.Coordinates[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch version {
|
||||||
|
case 300, 301:
|
||||||
|
if _, err := rd.Discard(144); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
case 302, 303:
|
||||||
|
if _, err := rd.Discard(96); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if version >= 302 {
|
||||||
|
// entry blocks
|
||||||
|
if _, err := rd.Discard(28 * 6); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// unknown1
|
||||||
|
if _, err := rd.Discard(44); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
//sound_effect
|
||||||
|
if _, err := rd.Discard(18); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// unknown2
|
||||||
|
if _, err := rd.Discard(18); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var cast uint32
|
||||||
|
|
||||||
|
if err := binary.Read(rd, end, &cast); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if version > 303 && (cast > 1) {
|
||||||
|
cf.Camp = CampSection{}
|
||||||
|
if err := binary.Read(rd, end, &cf.Camp.Params); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sz := int(cf.Camp.Params[1]) * int(cf.Camp.Params[2])
|
||||||
|
cf.Camp.Array = make([]byte, sz)
|
||||||
|
if _, err := io.ReadFull(rd, cf.Camp.Array); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type Plane struct {
|
||||||
|
Bitmap_id uint32
|
||||||
|
PlaneX int32
|
||||||
|
PlaneY int32
|
||||||
|
Opacity uint32
|
||||||
|
Blend BlendMode
|
||||||
|
FlagParam uint32
|
||||||
|
RenderFlag uint32
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
type BlendMode uint32
|
||||||
|
|
||||||
|
var (
|
||||||
|
BlendMode_None BlendMode = 0
|
||||||
|
BlendMode_Alpha BlendMode = 1
|
||||||
|
// Blend_ALPHA
|
||||||
|
BlendMode_InvertMul BlendMode = 2
|
||||||
|
// Color_Invert | Blend_MUL
|
||||||
|
BlendMode_Unknown3 BlendMode = 3
|
||||||
|
BlendMode_Add BlendMode = 4
|
||||||
|
BlendMode_InvertMul5 BlendMode = 5
|
||||||
|
// Color_Invert | Blend_MUL
|
||||||
|
BlendMode_Mul BlendMode = 6
|
||||||
|
BlendMode_Mul7 BlendMode = 7
|
||||||
|
BlendMode_Add8 BlendMode = 8
|
||||||
|
)
|
|
@ -0,0 +1,71 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"image"
|
||||||
|
"image/color"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Image struct {
|
||||||
|
Bpp uint32
|
||||||
|
Count uint32
|
||||||
|
Delay uint32
|
||||||
|
OffsetX int32
|
||||||
|
OffsetY int32
|
||||||
|
|
||||||
|
Width uint32
|
||||||
|
Height uint32
|
||||||
|
|
||||||
|
Size uint32
|
||||||
|
Data []byte
|
||||||
|
|
||||||
|
Frame image.Image
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Image) Decode(rd *bufio.Reader) error {
|
||||||
|
cf := image.NewRGBA64(image.Rect(0, 0, int(i.Width), int(i.Height)))
|
||||||
|
i.Frame = cf
|
||||||
|
switch i.Bpp {
|
||||||
|
case 8:
|
||||||
|
rd.Discard(int(i.Size))
|
||||||
|
return fmt.Errorf("bpp = 8, but no palette")
|
||||||
|
case 16:
|
||||||
|
var bgr uint16
|
||||||
|
for idx := 0; idx < int(i.Size/2); idx++ {
|
||||||
|
if err := binary.Read(rd, end, &bgr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
red := uint8(((0x7c00 & bgr) >> 10) * 255 / 31)
|
||||||
|
green := uint8(((0x3e0 & bgr) >> 5) * 255 / 31)
|
||||||
|
blue := uint8((0x1f & bgr) * 255 / 31)
|
||||||
|
if red != 0 && blue != 0 && green != 0 {
|
||||||
|
}
|
||||||
|
col := &color.RGBA{
|
||||||
|
red, green, blue,
|
||||||
|
0xff,
|
||||||
|
}
|
||||||
|
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
case 24:
|
||||||
|
i.Data = make([]byte, i.Size)
|
||||||
|
for idx := 0; idx < int(i.Size/3); idx++ {
|
||||||
|
rgb := [3]byte{}
|
||||||
|
_, err := io.ReadFull(rd, rgb[:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
col := &color.RGBA{
|
||||||
|
rgb[0], rgb[1], rgb[2],
|
||||||
|
0xff,
|
||||||
|
}
|
||||||
|
cf.Set(idx%int(i.Width), idx/int(i.Width), col)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unsupported bpp, %d", i.Bpp)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
type PaletteSection struct {
|
||||||
|
Version uint32
|
||||||
|
Param01 uint32
|
||||||
|
Param02 uint32
|
||||||
|
Param03 uint32
|
||||||
|
Param04 uint32
|
||||||
|
Divided bool
|
||||||
|
DataLength uint32
|
||||||
|
// Graphics::Palette color_data
|
||||||
|
}
|
||||||
|
|
||||||
|
type GawiSection struct {
|
||||||
|
Version uint32
|
||||||
|
Bpp uint32
|
||||||
|
IsCompressed bool
|
||||||
|
Params [4]uint32
|
||||||
|
BmpCount uint32
|
||||||
|
Size uint32
|
||||||
|
|
||||||
|
HasPalette bool
|
||||||
|
Palette *PaletteSection
|
||||||
|
// std::vector<uint32> bmp_offsets
|
||||||
|
Images []*Image
|
||||||
|
}
|
||||||
|
|
||||||
|
type Nori struct {
|
||||||
|
Version uint32
|
||||||
|
Params [5]uint32
|
||||||
|
AnimationCount uint32
|
||||||
|
SizeNoGawi uint32
|
||||||
|
TotalSize uint32
|
||||||
|
|
||||||
|
Gawi *GawiSection
|
||||||
|
Animations []*Animation
|
||||||
|
AnimationByKey map[string]*Animation
|
||||||
|
|
||||||
|
lastSignature [4]byte
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
nori, err := NewReader(rd).Decode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decode: %s", err)
|
||||||
|
}
|
||||||
|
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
nori, err := NewReader(rd).Decode()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("decode: %s", err)
|
||||||
|
}
|
||||||
|
t.Logf("\n nori: %+v\n gawi: %+v", nori, nori.Gawi)
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,165 @@
|
||||||
|
package nori
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"encoding/binary"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
var end = binary.LittleEndian
|
||||||
|
|
||||||
|
type Reader struct {
|
||||||
|
nori *Nori
|
||||||
|
|
||||||
|
r *bufio.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewReader(rd io.Reader) *Reader {
|
||||||
|
o := &Reader{
|
||||||
|
nori: &Nori{},
|
||||||
|
r: bufio.NewReader(rd),
|
||||||
|
}
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Reader) Decode() (*Nori, error) {
|
||||||
|
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if sig, target := string(n.nori.lastSignature[:]), "NORI"; sig != target {
|
||||||
|
return nil, fmt.Errorf("expected header %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &n.nori.Version); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, n.nori.Params[:]); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &n.nori.AnimationCount); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &n.nori.SizeNoGawi); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &n.nori.TotalSize); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := n.decodeGawi(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return n.nori, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Reader) decodeGawi() error {
|
||||||
|
g := &GawiSection{}
|
||||||
|
n.nori.Gawi = g
|
||||||
|
if _, err := io.ReadFull(n, n.nori.lastSignature[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if sig, target := string(n.nori.lastSignature[:]), "GAWI"; sig != target {
|
||||||
|
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &g.Version); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if g.Version != 300 {
|
||||||
|
return fmt.Errorf("bad ver: want 300, got %d", g.Version)
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &g.Bpp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
good := false
|
||||||
|
for _, v := range [3]uint32{8, 16, 24} {
|
||||||
|
if g.Bpp == v {
|
||||||
|
good = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !good {
|
||||||
|
return fmt.Errorf("bad bpp: %d", g.Bpp)
|
||||||
|
}
|
||||||
|
var container uint32
|
||||||
|
if err := binary.Read(n, end, &container); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.IsCompressed = (container == 1)
|
||||||
|
if err := binary.Read(n, end, &container); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.HasPalette = (container > 0)
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, g.Params[:]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &g.BmpCount); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := binary.Read(n, end, &g.Size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if g.HasPalette {
|
||||||
|
n.decodePalette()
|
||||||
|
}
|
||||||
|
if _, err := n.r.Discard(4 * int(g.BmpCount)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
g.Images = make([]*Image, int(g.BmpCount))
|
||||||
|
for i := range g.Images {
|
||||||
|
g.Images[i] = &Image{Bpp: g.Bpp}
|
||||||
|
if err := n.decodeImage(g.Images[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := n.r.Discard(4 * int(n.nori.AnimationCount)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
n.nori.Animations = make([]*Animation, n.nori.AnimationCount)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Reader) decodePalette() error {
|
||||||
|
if sig, target := string(n.nori.lastSignature[:]), "PAL_"; sig != target {
|
||||||
|
return fmt.Errorf("bad sig: want %s, got %s", target, sig)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
func (n *Reader) decodeImage(img *Image) error {
|
||||||
|
if err := binary.Read(n, end, &img.Count); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if img.Count != 1 {
|
||||||
|
return fmt.Errorf("img count should be 1")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.Size); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.Width); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.Height); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.Delay); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.OffsetX); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := binary.Read(n, end, &img.OffsetY); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := img.Decode(n.r); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *Reader) Read(b []byte) (int, error) {
|
||||||
|
return n.r.Read(b)
|
||||||
|
}
|
Loading…
Reference in New Issue