qmuntal/gltf

View on GitHub
binary/encode.go

Summary

Maintainability
A
0 mins
Test Coverage
package binary

import (
    "bytes"
    "encoding/binary"
    "image/color"
    "io"

    "github.com/qmuntal/gltf"
)

// Read reads structured binary data from b into data.
// byteStride can be zero for non-interleaved buffer views.
//
// Data should be a slice of glTF predefined fixed-size types.
// If data length is greater than the length of b, Read returns io.ErrShortBuffer.
func Read(b []byte, byteStride uint32, data any) error {
    c, t, n := Type(data)
    size := gltf.SizeOfElement(c, t)
    if byteStride == 0 {
        byteStride = size
    }
    e := int(byteStride)
    high := int(n) * e
    if byteStride != size {
        high -= int(byteStride - size)
    }
    if len(b) < high {
        return io.ErrShortBuffer
    }
    switch data := data.(type) {
    case []color.RGBA:
        for i := range data {
            c := Ubyte.Vec4(b[e*i:])
            data[i] = color.RGBA{R: c[0], G: c[1], B: c[2], A: c[3]}
        }
    case []color.RGBA64:
        for i := range data {
            c := Ushort.Vec4(b[e*i:])
            data[i] = color.RGBA64{R: c[0], G: c[1], B: c[2], A: c[3]}
        }
    case []int8:
        for i, x := range b {
            data[i] = int8(x)
        }
    case [][2]int8:
        for i := range data {
            data[i] = Byte.Vec2(b[e*i:])
        }
    case [][3]int8:
        for i := range data {
            data[i] = Byte.Vec3(b[e*i:])
        }
    case [][4]int8:
        for i := range data {
            data[i] = Byte.Vec4(b[e*i:])
        }
    case [][2][2]int8:
        for i := range data {
            data[i] = Byte.Mat2(b[e*i:])
        }
    case [][3][3]int8:
        for i := range data {
            data[i] = Byte.Mat3(b[e*i:])
        }
    case [][4][4]int8:
        for i := range data {
            data[i] = Byte.Mat4(b[e*i:])
        }
    case []uint8:
        if byteStride != 1 {
            copy(data, b)
        } else {
            for i := range data {
                data[i] = Ubyte.Scalar(b[e*i:])
            }
        }
    case [][2]uint8:
        for i := range data {
            data[i] = Ubyte.Vec2(b[e*i:])
        }
    case [][3]uint8:
        for i := range data {
            data[i] = Ubyte.Vec3(b[e*i:])
        }
    case [][4]uint8:
        for i := range data {
            data[i] = Ubyte.Vec4(b[e*i:])
        }
    case [][2][2]uint8:
        for i := range data {
            data[i] = Ubyte.Mat2(b[e*i:])
        }
    case [][3][3]uint8:
        for i := range data {
            data[i] = Ubyte.Mat3(b[e*i:])
        }
    case [][4][4]uint8:
        for i := range data {
            data[i] = Ubyte.Mat4(b[e*i:])
        }
    case []int16:
        for i := range data {
            data[i] = Short.Scalar(b[e*i:])
        }
    case [][2]int16:
        for i := range data {
            data[i] = Short.Vec2(b[e*i:])
        }
    case [][3]int16:
        for i := range data {
            data[i] = Short.Vec3(b[e*i:])
        }
    case [][4]int16:
        for i := range data {
            data[i] = Short.Vec4(b[e*i:])
        }
    case [][2][2]int16:
        for i := range data {
            data[i] = Short.Mat2(b[e*i:])
        }
    case [][3][3]int16:
        for i := range data {
            data[i] = Short.Mat3(b[e*i:])
        }
    case [][4][4]int16:
        for i := range data {
            data[i] = Short.Mat4(b[e*i:])
        }
    case []uint16:
        for i := range data {
            data[i] = Ushort.Scalar(b[e*i:])
        }
    case [][2]uint16:
        for i := range data {
            data[i] = Ushort.Vec2(b[e*i:])
        }
    case [][3]uint16:
        for i := range data {
            data[i] = Ushort.Vec3(b[e*i:])
        }
    case [][4]uint16:
        for i := range data {
            data[i] = Ushort.Vec4(b[e*i:])
        }
    case [][2][2]uint16:
        for i := range data {
            data[i] = Ushort.Mat2(b[e*i:])
        }
    case [][3][3]uint16:
        for i := range data {
            data[i] = Ushort.Mat3(b[e*i:])
        }
    case [][4][4]uint16:
        for i := range data {
            data[i] = Ushort.Mat4(b[e*i:])
        }
    case []float32:
        for i := range data {
            data[i] = Float.Scalar(b[e*i:])
        }
    case [][2]float32:
        for i := range data {
            data[i] = Float.Vec2(b[e*i:])
        }
    case [][3]float32:
        for i := range data {
            data[i] = Float.Vec3(b[e*i:])
        }
    case [][4]float32:
        for i := range data {
            data[i] = Float.Vec4(b[e*i:])
        }
    case [][2][2]float32:
        for i := range data {
            data[i] = Float.Mat2(b[e*i:])
        }
    case [][3][3]float32:
        for i := range data {
            data[i] = Float.Mat3(b[e*i:])
        }
    case [][4][4]float32:
        for i := range data {
            data[i] = Float.Mat4(b[e*i:])
        }
    case []uint32:
        for i := range data {
            data[i] = Uint.Scalar(b[e*i:])
        }
    case [][2]uint32:
        for i := range data {
            data[i] = Uint.Vec2(b[e*i:])
        }
    case [][3]uint32:
        for i := range data {
            data[i] = Uint.Vec3(b[e*i:])
        }
    case [][4]uint32:
        for i := range data {
            data[i] = Uint.Vec4(b[e*i:])
        }
    case [][2][2]uint32:
        for i := range data {
            data[i] = Uint.Mat2(b[e*i:])
        }
    case [][3][3]uint32:
        for i := range data {
            data[i] = Uint.Mat3(b[e*i:])
        }
    case [][4][4]uint32:
        for i := range data {
            data[i] = Uint.Mat4(b[e*i:])
        }
    default:
        panic("unsupported type")
    }
    return nil
}

// Write writes the binary representation of data into b.
// If stride is diferent than zero data will be interleaved.
//
// Data must be a slice of glTF predefined fixed-size types,
// else it fallbacks to `encoding/binary.Write`.
func Write(b []byte, stride uint32, data any) error {
    c, t, n := Type(data)
    if n == 0 {
        return binary.Write(bytes.NewBuffer(b), binary.LittleEndian, data)
    }
    e := int(stride)
    sizeOfElement := int(gltf.SizeOfElement(c, t))
    if stride == 0 {
        e = sizeOfElement
    }
    if len(b) < e*(int(n)-1)+sizeOfElement {
        return io.ErrShortBuffer
    }
    switch data := data.(type) {
    case []color.RGBA:
        for i, x := range data {
            Ubyte.PutVec4(b[e*i:], [4]uint8{x.R, x.G, x.B, x.A})
        }
    case []color.RGBA64:
        for i, x := range data {
            Ushort.PutVec4(b[e*i:], [4]uint16{x.R, x.G, x.B, x.A})
        }
    case []int8:
        for i, x := range data {
            b[e*i] = byte(x)
        }
    case [][2]int8:
        for i := range data {
            Byte.PutVec2(b[e*i:], data[i])
        }
    case [][3]int8:
        for i := range data {
            Byte.PutVec3(b[e*i:], data[i])
        }
    case [][4]int8:
        for i := range data {
            Byte.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]int8:
        for i := range data {
            Byte.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]int8:
        for i := range data {
            Byte.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]int8:
        for i := range data {
            Byte.PutMat4(b[e*i:], data[i])
        }
    case []uint8:
        copy(b, data)
    case [][2]uint8:
        for i := range data {
            Ubyte.PutVec2(b[e*i:], data[i])
        }
    case [][3]uint8:
        for i := range data {
            Ubyte.PutVec3(b[e*i:], data[i])
        }
    case [][4]uint8:
        for i := range data {
            Ubyte.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]uint8:
        for i := range data {
            Ubyte.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]uint8:
        for i := range data {
            Ubyte.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]uint8:
        for i := range data {
            Ubyte.PutMat4(b[e*i:], data[i])
        }
    case []int16:
        for i := range data {
            Short.PutScalar(b[e*i:], data[i])
        }
    case [][2]int16:
        for i := range data {
            Short.PutVec2(b[e*i:], data[i])
        }
    case [][3]int16:
        for i := range data {
            Short.PutVec3(b[e*i:], data[i])
        }
    case [][4]int16:
        for i := range data {
            Short.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]int16:
        for i := range data {
            Short.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]int16:
        for i := range data {
            Short.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]int16:
        for i := range data {
            Short.PutMat4(b[e*i:], data[i])
        }
    case []uint16:
        for i := range data {
            Ushort.PutScalar(b[e*i:], data[i])
        }
    case [][2]uint16:
        for i := range data {
            Ushort.PutVec2(b[e*i:], data[i])
        }
    case [][3]uint16:
        for i := range data {
            Ushort.PutVec3(b[e*i:], data[i])
        }
    case [][4]uint16:
        for i := range data {
            Ushort.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]uint16:
        for i := range data {
            Ushort.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]uint16:
        for i := range data {
            Ushort.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]uint16:
        for i := range data {
            Ushort.PutMat4(b[e*i:], data[i])
        }
    case []float32:
        for i := range data {
            Float.PutScalar(b[e*i:], data[i])
        }
    case [][2]float32:
        for i := range data {
            Float.PutVec2(b[e*i:], data[i])
        }
    case [][3]float32:
        for i := range data {
            Float.PutVec3(b[e*i:], data[i])
        }
    case [][4]float32:
        for i := range data {
            Float.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]float32:
        for i := range data {
            Float.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]float32:
        for i := range data {
            Float.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]float32:
        for i := range data {
            Float.PutMat4(b[e*i:], data[i])
        }
    case []uint32:
        for i := range data {
            Uint.PutScalar(b[e*i:], data[i])
        }
    case [][2]uint32:
        for i := range data {
            Uint.PutVec2(b[e*i:], data[i])
        }
    case [][3]uint32:
        for i := range data {
            Uint.PutVec3(b[e*i:], data[i])
        }
    case [][4]uint32:
        for i := range data {
            Uint.PutVec4(b[e*i:], data[i])
        }
    case [][2][2]uint32:
        for i := range data {
            Uint.PutMat2(b[e*i:], data[i])
        }
    case [][3][3]uint32:
        for i := range data {
            Uint.PutMat3(b[e*i:], data[i])
        }
    case [][4][4]uint32:
        for i := range data {
            Uint.PutMat4(b[e*i:], data[i])
        }
    }
    return nil
}