file reading

This commit is contained in:
elee 2022-03-25 00:14:03 -05:00
commit 023563f713
10 changed files with 476 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
bin/
out/
dist/
*.exe
*.out
*.bin
*test.png

139
common/nori/animation.go Normal file
View File

@ -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
}

18
common/nori/blend.go Normal file
View File

@ -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
)

71
common/nori/image.go Normal file
View File

@ -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)
}
}

40
common/nori/nori.go Normal file
View File

@ -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
}

30
common/nori/nori_test.go Normal file
View File

@ -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.

165
common/nori/reader.go Normal file
View File

@ -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)
}

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.tuxpa.in/a/gotagonist
go 1.18