package threedb import ( "encoding/binary" "errors" "io" "log" ) type Decoder struct { reader io.ReadSeeker } func NewDecoder(reader io.ReadSeeker) *Decoder { return &Decoder{reader: reader} } func (dec *Decoder) Decode(model *Model) error { if model == nil { return errors.New("model is nil") } var err error if model.DBVersion, err = dec.readString(); err != nil { return err } if model.Name, err = dec.readString(); err != nil { return err } if err = dec.readMaterials(model); err != nil { return err } if err = dec.readMeshes(model); err != nil { return err } if err = dec.readObjects(model); err != nil { return err } if err = dec.readAnimations(model); err != nil { return err } if err = dec.readShadows(model); err != nil { return err } if err = dec.readCubeMaps(model); err != nil { return err } if err = dec.readData(model); err != nil { return err } return nil } func (dec *Decoder) seek(offset int64) (err error) { _, err = dec.reader.Seek(offset, io.SeekCurrent) return } func (dec *Decoder) read(dst any) error { return binary.Read(dec.reader, binary.LittleEndian, dst) } func (dec *Decoder) readUInt8() (result uint8, err error) { err = dec.read(&result) return } func (dec *Decoder) readUInt16() (result uint16, err error) { err = dec.read(&result) return } func (dec *Decoder) readUInt32() (result uint32, err error) { err = dec.read(&result) return } func (dec *Decoder) readFloat32() (result float32, err error) { err = dec.read(&result) return } func (dec *Decoder) readString() (string, error) { length, err := dec.readUInt32() if err != nil { return "", err } buf := make([]byte, length) if err = dec.read(&buf); err != nil { return "", err } return string(buf), nil } func (dec *Decoder) readVector() (*Vector, error) { var vec Vector var err error if vec[0], err = dec.readFloat32(); err != nil { return nil, err } if vec[1], err = dec.readFloat32(); err != nil { return nil, err } if vec[2], err = dec.readFloat32(); err != nil { return nil, err } return &vec, nil } func (dec *Decoder) readMaterials(model *Model) error { materialCount, err := dec.readUInt16() if err != nil { return err } count := int(materialCount) for i := 0; i < count; i++ { material := Material{} if material.Name, err = dec.readString(); err != nil { return err } if material.Path, err = dec.readString(); err != nil { return err } if material.Unknown, err = dec.readUInt32(); err != nil { return err } model.Materials = append(model.Materials, material) } return nil } func (dec *Decoder) readMeshes(model *Model) error { meshCount, err := dec.readUInt32() if err != nil { return err } count := int(meshCount) for i := 0; i < count; i++ { mesh := Mesh{} if err = dec.readMeshLink(&mesh); err != nil { return err } if mesh.Vector1, err = dec.readVector(); err != nil { return err } if mesh.Vector2, err = dec.readVector(); err != nil { return err } _ = dec.seek(0x80) if mesh.Shadow, err = dec.readUInt16(); err != nil { return err } // Mesh Shadow Index ? _ = dec.seek(0x30) if mesh.CMap, err = dec.readUInt16(); err != nil { return err } // Mesh CMap Index ? model.Meshes = append(model.Meshes, mesh) } return nil } func (dec *Decoder) readMeshLink(mesh *Mesh) error { meshLinkCount, err := dec.readUInt16() if err != nil { return err } count := int(meshLinkCount) for i := 0; i < count; i++ { meshLink := MeshLink{} if meshLink.Material, err = dec.readUInt16(); err != nil { return err } if meshLink.Unknown, err = dec.readUInt16(); err != nil { return err } if meshLink.Triangles, err = dec.readUInt16(); err != nil { return err } if meshLink.TextureCoordinates, err = dec.readUInt16(); err != nil { return err } if meshLink.Points, err = dec.readUInt16(); err != nil { return err } if meshLink.Brightness, err = dec.readUInt16(); err != nil { return err } mesh.Links = append(mesh.Links, meshLink) } return nil } func (dec *Decoder) readObjects(model *Model) error { keyValuePairCount, err := dec.readUInt16() if err != nil { return err } count := int(keyValuePairCount) if count > 0 && model.Objects == nil { model.Objects = make(map[string][]uint32) } for i := 0; i < count; i++ { var key string if key, err = dec.readString(); err != nil { return err } var objectCount uint16 if objectCount, err = dec.readUInt16(); err != nil { return err } model.Objects[key] = make([]uint32, objectCount) for j := 0; j < int(objectCount); j++ { var n uint32 if n, err = dec.readUInt32(); err != nil { return err } model.Objects[key] = append(model.Objects[key], n) } } return nil } func (dec *Decoder) readAnimations(model *Model) error { animationCount, err := dec.readUInt16() if err != nil { return err } count := int(animationCount) for i := 0; i < count; i++ { animation := Animation{} if animation.Name, err = dec.readString(); err != nil { return err } var meshIndexesCount uint16 if meshIndexesCount, err = dec.readUInt16(); err != nil { return err } animation.MeshIndexes = make([]uint32, meshIndexesCount) for j := 0; j < int(meshIndexesCount); j++ { var n uint32 if n, err = dec.readUInt32(); err != nil { return err } animation.MeshIndexes[j] = n } if animation.Unknown, err = dec.readUInt16(); err != nil { return err } if animation.Unknown1, err = dec.readUInt16(); err != nil { return err } if animation.Unknown2, err = dec.readUInt16(); err != nil { return err } //if animation.Unknown1, err = dec.readFloat32(); err != nil { // return err //} if animation.Unknown3, err = dec.readString(); err != nil { return err } if animation.MoveVector, err = dec.readVector(); err != nil { return err } if animation.RotationVector, err = dec.readVector(); err != nil { return err } model.Animations = append(model.Animations, animation) } return nil } func (dec *Decoder) readShadows(_ *Model) error { shadowCount, err := dec.readUInt16() if err != nil { return err } count := int(shadowCount) for i := 0; i < count; i++ { // Skip // TODO: возможно это картинка 32х32 _ = dec.seek(32 * 32) } return nil } func (dec *Decoder) readCubeMaps(_ *Model) error { cubeMapCount, err := dec.readUInt16() if err != nil { return err } count := int(cubeMapCount) for i := 0; i < count; i++ { var width, height uint16 if width, err = dec.readUInt16(); err != nil { return err } if height, err = dec.readUInt16(); err != nil { return err } _, _ = dec.readUInt16() _, _ = dec.readUInt16() // Skip pixel data _ = dec.seek(int64(width * height)) } return nil } func (dec *Decoder) readData(model *Model) error { var ( triangleCount uint16 trianglesCounts []uint16 textureCoordCount uint16 textureCoordCounts []uint16 pointCount uint16 pointCounts []uint16 brightnessCount uint16 brightnessCounts []uint16 unknownCount uint32 cnt uint16 err error ) if triangleCount, err = dec.readUInt16(); err != nil { return err } if textureCoordCount, err = dec.readUInt16(); err != nil { return err } if pointCount, err = dec.readUInt16(); err != nil { return err } if brightnessCount, err = dec.readUInt16(); err != nil { return err } if unknownCount, err = dec.readUInt32(); err != nil { return err } log.Println("unknownCount:", unknownCount) for i := 0; i < int(triangleCount); i++ { if cnt, err = dec.readUInt16(); err != nil { return err } trianglesCounts = append(trianglesCounts, cnt) } for i := 0; i < int(textureCoordCount); i++ { if cnt, err = dec.readUInt16(); err != nil { return err } textureCoordCounts = append(textureCoordCounts, cnt) } for i := 0; i < int(pointCount); i++ { if cnt, err = dec.readUInt16(); err != nil { return err } pointCounts = append(pointCounts, cnt) } for i := 0; i < int(brightnessCount); i++ { if cnt, err = dec.readUInt16(); err != nil { return err } brightnessCounts = append(brightnessCounts, cnt) } for i := 0; i < int(unknownCount); i++ { //x, err := dec.readFloat32() //if err != nil { // return err //} //y, err := dec.readFloat32() //if err != nil { // return err //} //vec, err := dec.readVector() //if err != nil { // return err //} //log.Println(Coordinate{x, y}, vec) //if cnt, err = dec.readUInt16(); err != nil { // return err //} //log.Println("cnt", cnt) //buff := make([]byte, 20) //err = dec.read(&buff) //if err != nil { // return err //} //log.Println(buff) //vec, err := dec.readVector() //if err != nil { // return err //} //log.Println(vec) _ = dec.seek(20) } if err = dec.readTriangles(model, int(triangleCount), trianglesCounts); err != nil { return err } if err = dec.readTextureCoordinates(model, int(textureCoordCount), textureCoordCounts); err != nil { return err } if err = dec.readPoint(model, int(pointCount), pointCounts); err != nil { return err } if err = dec.readBrightness(model, int(brightnessCount), brightnessCounts); err != nil { return err } return nil } func (dec *Decoder) readTriangles(model *Model, count int, counts []uint16) error { for i := 0; i < count; i++ { cnt := int(counts[i]) var triangles []uint16 for j := 0; j < cnt; j++ { n, err := dec.readUInt16() if err != nil { return err } triangles = append(triangles, n) } model.Triangles = append(model.Triangles, triangles) } return nil } func (dec *Decoder) readTextureCoordinates(model *Model, count int, counts []uint16) error { for i := 0; i < count; i++ { cnt := int(counts[i]) var cords []Coordinate for j := 0; j < cnt; j++ { cord := Coordinate{} u, err := dec.readFloat32() if err != nil { return err } v, err := dec.readFloat32() if err != nil { return err } cord.Set(u, v) cords = append(cords, cord) } model.TextureCoordinates = append(model.TextureCoordinates, cords) } return nil } func (dec *Decoder) readPoint(model *Model, count int, counts []uint16) error { for i := 0; i < count; i++ { cnt := int(counts[i]) var vectors []Vector for j := 0; j < cnt; j++ { vec := Vector{} ux, err := dec.readUInt16() if err != nil { return err } uy, err := dec.readUInt16() if err != nil { return err } uz, err := dec.readUInt16() if err != nil { return err } vec.Set(float32(ux)/float32(0xffff), float32(uy)/float32(0xffff), float32(uz)/float32(0xffff)) vectors = append(vectors, vec) } model.Points = append(model.Points, vectors) } return nil } func (dec *Decoder) readBrightness(model *Model, count int, counts []uint16) error { for i := 0; i < count; i++ { cnt := int(counts[i]) var brightness []byte for j := 0; j < cnt; j++ { b, err := dec.readUInt8() if err != nil { return err } brightness = append(brightness, b) } model.Brightness = append(model.Brightness, brightness) } return nil }