Skip to content

Commit

Permalink
Merge 706e479 into d503182
Browse files Browse the repository at this point in the history
  • Loading branch information
qmuntal committed Oct 29, 2020
2 parents d503182 + 706e479 commit eb539ba
Show file tree
Hide file tree
Showing 26 changed files with 1,852 additions and 435 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ func main() {
doc := &gltf.Document{
Accessors: []*gltf.Accessor{
{BufferView: gltf.Index(0), ComponentType: gltf.ComponentUShort, Count: 36, Type: gltf.AccessorScalar},
{BufferView: gltf.Index(1), ComponentType: gltf.ComponentFloat, Count: 24, Max: []float64{0.5, 0.5, 0.5}, Min: []float64{-0.5, -0. -0.5}, Type: gltf.AccessorVec3},
{BufferView: gltf.Index(1), ComponentType: gltf.ComponentFloat, Count: 24, Max: []float32{0.5, 0.5, 0.5}, Min: []float32{-0.5, -0. -0.5}, Type: gltf.AccessorVec3},
{BufferView: gltf.Index(2), ComponentType: gltf.ComponentFloat, Count: 24, Type: gltf.AccessorVec3},
{BufferView: gltf.Index(3), ComponentType: gltf.ComponentFloat, Count: 24, Type: gltf.AccessorVec4},
{BufferView: gltf.Index(4), ComponentType: gltf.ComponentFloat, Count: 24, Type: gltf.AccessorVec2},
Expand All @@ -148,7 +148,7 @@ func main() {
Buffers: []*gltf.Buffer{{ByteLength: 1224, URI: bufferData}},
Materials: []*gltf.Material{{
Name: "Default", AlphaMode: gltf.AlphaOpaque, AlphaCutoff: gltf.Float64(0.5),
PBRMetallicRoughness: &gltf.PBRMetallicRoughness{BaseColorFactor: &gltf.RGBA{R: 0.8, G: 0.8, B: 0.8, A: 1}, MetallicFactor: gltf.Float64(0.1), RoughnessFactor: gltf.Float64(0.99)},
PBRMetallicRoughness: &gltf.PBRMetallicRoughness{BaseColorFactor: &[4]float32{0.8, 0.8, 0.8, 0.5}, MetallicFactor: gltf.Float64(0.1), RoughnessFactor: gltf.Float64(0.99)},
}},
Meshes: []*gltf.Mesh{{Name: "Cube", Primitives: []*gltf.Primitive{{Indices: gltf.Index(0), Material: gltf.Index(0), Mode: gltf.PrimitiveTriangles, Attributes: map[string]uint32{"POSITION": 1, "COLOR_0": 3, "NORMAL": 2, "TEXCOORD_0": 4}}}}},
Nodes: []*gltf.Node{
Expand Down
49 changes: 21 additions & 28 deletions binary/encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ import (
"encoding/binary"
"image/color"
"io"

"github.com/qmuntal/gltf"
)

// Read reads structured binary data from b into data.
// Data should be a slice of glTF predefined fixed-size types,
// else it fallbacks to `encoding/binary.Read`.
// 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, data interface{}) error {
func Read(b []byte, byteStride uint32, data interface{}) error {
c, t, n := Type(data)
if n == 0 {
return binary.Read(bytes.NewReader(b), binary.LittleEndian, data)
size := SizeOfElement(c, t)
if byteStride == 0 {
byteStride = size
}
e := int(byteStride)
high := int(n) * e
if byteStride != size {
high -= int(size)
}
e := int(SizeOfElement(c, t))
if len(b) < int(n)*e {
if len(b) < high {
return io.ErrShortBuffer
}
switch data := data.(type) {
Expand All @@ -34,16 +37,6 @@ func Read(b []byte, data interface{}) error {
c := Ushort.Vec4(b[e*i:])
data[i] = color.RGBA64{R: c[0], G: c[1], B: c[2], A: c[3]}
}
case []gltf.RGBA:
for i := range data {
c := Float.Vec4(b[e*i:])
data[i] = gltf.RGBA{R: float64(c[0]), G: float64(c[1]), B: float64(c[2]), A: float64(c[3])}
}
case []gltf.RGB:
for i := range data {
c := Float.Vec3(b[e*i:])
data[i] = gltf.RGB{R: float64(c[0]), G: float64(c[1]), B: float64(c[2])}
}
case []int8:
for i, x := range b {
data[i] = int8(x)
Expand Down Expand Up @@ -73,7 +66,13 @@ func Read(b []byte, data interface{}) error {
data[i] = Byte.Mat4(b[e*i:])
}
case []uint8:
copy(data, b)
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:])
Expand Down Expand Up @@ -210,6 +209,8 @@ func Read(b []byte, data interface{}) error {
for i := range data {
data[i] = Uint.Mat4(b[e*i:])
}
default:
panic("unsupported type")
}
return nil
}
Expand Down Expand Up @@ -240,14 +241,6 @@ func Write(b []byte, stride uint32, data interface{}) error {
for i, x := range data {
Ushort.PutVec4(b[e*i:], [4]uint16{x.R, x.G, x.B, x.A})
}
case []gltf.RGBA:
for i, x := range data {
Float.PutVec4(b[e*i:], [4]float32{float32(x.R), float32(x.G), float32(x.B), float32(x.A)})
}
case []gltf.RGB:
for i, x := range data {
Float.PutVec3(b[e*i:], [3]float32{float32(x.R), float32(x.G), float32(x.B)})
}
case []int8:
for i, x := range data {
b[e*i] = byte(x)
Expand Down
10 changes: 1 addition & 9 deletions binary/encode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"math"
"reflect"
"testing"

"github.com/qmuntal/gltf"
)

func buildBuffer1(n int, empty ...int) []byte {
Expand Down Expand Up @@ -59,7 +57,6 @@ func TestRead(t *testing.T) {
want interface{}
wantErr bool
}{
{"not suported", args{make([]byte, 2), 1}, nil, true},
{"small", args{[]byte{0, 0}, []int8{1, 2, 3}}, []int8{0, 0}, true},
{"empty", args{make([]byte, 0), []int8{}}, []int8{}, false},
{"int8", args{buildBuffer1(4), make([]int8, 4)}, []int8{1, 2, 3, 4}, false},
Expand Down Expand Up @@ -166,12 +163,10 @@ func TestRead(t *testing.T) {
}, false},
{"color.RGBA", args{buildBuffer1(2 * 4), make([]color.RGBA, 2)}, []color.RGBA{{1, 2, 3, 4}, {5, 6, 7, 8}}, false},
{"color.RGBA64", args{buildBuffer2(2 * 4), make([]color.RGBA64, 2)}, []color.RGBA64{{1, 2, 3, 4}, {5, 6, 7, 8}}, false},
{"gltf.RGBA", args{buildBufferF(2 * 4), make([]gltf.RGBA, 2)}, []gltf.RGBA{{R: 1, G: 2, B: 3, A: 4}, {R: 5, G: 6, B: 7, A: 8}}, false},
{"gltf.RGB", args{buildBufferF(2 * 3), make([]gltf.RGB, 2)}, []gltf.RGB{{R: 1, G: 2, B: 3}, {R: 4, G: 5, B: 6}}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := Read(tt.args.b, tt.args.data); (err != nil) != tt.wantErr {
if err := Read(tt.args.b, 0, tt.args.data); (err != nil) != tt.wantErr {
t.Errorf("Read() error = %v, wantErr %v", err, tt.wantErr)
}
if !tt.wantErr && !reflect.DeepEqual(tt.args.data, tt.want) {
Expand All @@ -192,7 +187,6 @@ func TestWrite(t *testing.T) {
want []byte
wantErr bool
}{
{"not suported", args{2, 1}, nil, true},
{"small", args{2, []int8{1, 2, 3}}, []byte{1, 2, 3}, true},
{"empty", args{0, []int8{}}, []byte{}, false},
{"int8", args{4, []int8{1, 2, 3, 4}}, buildBuffer1(4), false},
Expand Down Expand Up @@ -299,8 +293,6 @@ func TestWrite(t *testing.T) {
}}, buildBufferF(32), false},
{"color.RGBA", args{8, []color.RGBA{{1, 2, 3, 4}, {5, 6, 7, 8}}}, buildBuffer1(2 * 4), false},
{"color.RGBA64", args{16, []color.RGBA64{{1, 2, 3, 4}, {5, 6, 7, 8}}}, buildBuffer2(2 * 4), false},
{"gltf.RGBA", args{32, []gltf.RGBA{{R: 1, G: 2, B: 3, A: 4}, {R: 5, G: 6, B: 7, A: 8}}}, buildBufferF(2 * 4), false},
{"gltf.RGB", args{24, []gltf.RGB{{R: 1, G: 2, B: 3}, {R: 4, G: 5, B: 6}}}, buildBufferF(2 * 3), false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
4 changes: 2 additions & 2 deletions binary/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ func ExampleRead() {
sizeIndices := uint32(len(indices)) * binary.SizeOfElement(gltf.ComponentUbyte, gltf.AccessorScalar)

// Write
binary.Read(b, indices)
binary.Read(b[sizeIndices:], vertices)
binary.Read(b, 0, indices)
binary.Read(b[sizeIndices:], 0, vertices)

fmt.Println(indices)
fmt.Println(vertices)
Expand Down
135 changes: 86 additions & 49 deletions binary/size.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package binary

import (
"fmt"
"image/color"
"reflect"

Expand Down Expand Up @@ -28,102 +29,138 @@ func SizeOfElement(c gltf.ComponentType, t gltf.AccessorType) uint32 {
return c.ByteSize() * t.Components()
}

// MakeSlice returns the slice type associated with c and t and with the given element count.
// For example, if c is gltf.ComponentFloat and t is gltf.AccessorVec3
// then MakeSlice(c, t, 5) is equivalent to make([][3]float32, 5).
func MakeSlice(c gltf.ComponentType, t gltf.AccessorType, count uint32) interface{} {
var tp reflect.Type
switch c {
case gltf.ComponentUbyte:
tp = reflect.TypeOf((*uint8)(nil))
case gltf.ComponentByte:
tp = reflect.TypeOf((*int8)(nil))
case gltf.ComponentUshort:
tp = reflect.TypeOf((*uint16)(nil))
case gltf.ComponentShort:
tp = reflect.TypeOf((*int16)(nil))
case gltf.ComponentUint:
tp = reflect.TypeOf((*uint32)(nil))
case gltf.ComponentFloat:
tp = reflect.TypeOf((*float32)(nil))
}
tp = tp.Elem()
switch t {
case gltf.AccessorVec2:
tp = reflect.ArrayOf(2, tp)
case gltf.AccessorVec3:
tp = reflect.ArrayOf(3, tp)
case gltf.AccessorVec4:
tp = reflect.ArrayOf(4, tp)
case gltf.AccessorMat2:
tp = reflect.ArrayOf(2, reflect.ArrayOf(2, tp))
case gltf.AccessorMat3:
tp = reflect.ArrayOf(3, reflect.ArrayOf(3, tp))
case gltf.AccessorMat4:
tp = reflect.ArrayOf(4, reflect.ArrayOf(4, tp))
}
return reflect.MakeSlice(reflect.SliceOf(tp), int(count), int(count)).Interface()
}

// Type returns the associated glTF type data.
// If data is an slice, it also returns the length of the slice.
// If data does not have an associated glTF type length will be 0.
func Type(data interface{}) (c gltf.ComponentType, t gltf.AccessorType, length uint32) {
// It panics if data is not an slice.
func Type(data interface{}) (c gltf.ComponentType, t gltf.AccessorType, count uint32) {
v := reflect.ValueOf(data)
switch v.Kind() {
case reflect.Slice:
length = uint32(v.Len())
if v.Kind() != reflect.Slice {
panic(fmt.Sprintf("go3mf: binary.Type expecting a slice but got %s", v.Kind()))
}
count = uint32(v.Len())
switch data.(type) {
case []int8, int8:
case []int8:
c, t = gltf.ComponentByte, gltf.AccessorScalar
case [][2]int8, [2]int8:
case [][2]int8:
c, t = gltf.ComponentByte, gltf.AccessorVec2
case [][3]int8, [3]int8:
case [][3]int8:
c, t = gltf.ComponentByte, gltf.AccessorVec3
case [][4]int8, [4]int8:
case [][4]int8:
c, t = gltf.ComponentByte, gltf.AccessorVec4
case [][2][2]int8, [2][2]int8:
case [][2][2]int8:
c, t = gltf.ComponentByte, gltf.AccessorMat2
case [][3][3]int8, [3][3]int8:
case [][3][3]int8:
c, t = gltf.ComponentByte, gltf.AccessorMat3
case [][4][4]int8, [4][4]int8:
case [][4][4]int8:
c, t = gltf.ComponentByte, gltf.AccessorMat4
case []uint8, uint8:
case []uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorScalar
case [][2]uint8, [2]uint8:
case [][2]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorVec2
case [][3]uint8, [3]uint8:
case [][3]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorVec3
case []color.RGBA, color.RGBA, [][4]uint8, [4]uint8:
case []color.RGBA, [][4]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorVec4
case [][2][2]uint8, [2][2]uint8:
case [][2][2]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorMat2
case [][3][3]uint8, [3][3]uint8:
case [][3][3]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorMat3
case [][4][4]uint8, [4][4]uint8:
case [][4][4]uint8:
c, t = gltf.ComponentUbyte, gltf.AccessorMat4
case []int16, int16:
case []int16:
c, t = gltf.ComponentShort, gltf.AccessorScalar
case [][2]int16, [2]int16:
case [][2]int16:
c, t = gltf.ComponentShort, gltf.AccessorVec2
case [][3]int16, [3]int16:
case [][3]int16:
c, t = gltf.ComponentShort, gltf.AccessorVec3
case [][4]int16, [4]int16:
case [][4]int16:
c, t = gltf.ComponentShort, gltf.AccessorVec4
case [][2][2]int16, [2][2]int16:
case [][2][2]int16:
c, t = gltf.ComponentShort, gltf.AccessorMat2
case [][3][3]int16, [3][3]int16:
case [][3][3]int16:
c, t = gltf.ComponentShort, gltf.AccessorMat3
case [][4][4]int16, [4][4]int16:
case [][4][4]int16:
c, t = gltf.ComponentShort, gltf.AccessorMat4
case []uint16, uint16:
case []uint16:
c, t = gltf.ComponentUshort, gltf.AccessorScalar
case [][2]uint16, [2]uint16:
case [][2]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorVec2
case [][3]uint16, [3]uint16:
case [][3]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorVec3
case []color.RGBA64, color.RGBA64, [][4]uint16, [4]uint16:
case []color.RGBA64, [][4]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorVec4
case [][2][2]uint16, [2][2]uint16:
case [][2][2]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorMat2
case [][3][3]uint16, [3][3]uint16:
case [][3][3]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorMat3
case [][4][4]uint16, [4][4]uint16:
case [][4][4]uint16:
c, t = gltf.ComponentUshort, gltf.AccessorMat4
case []uint32, uint32:
case []uint32:
c, t = gltf.ComponentUint, gltf.AccessorScalar
case [][2]uint32, [2]uint32:
case [][2]uint32:
c, t = gltf.ComponentUint, gltf.AccessorVec2
case [][3]uint32, [3]uint32:
case [][3]uint32:
c, t = gltf.ComponentUint, gltf.AccessorVec3
case [][4]uint32, [4]uint32:
case [][4]uint32:
c, t = gltf.ComponentUint, gltf.AccessorVec4
case [][2][2]uint32, [2][2]uint32:
case [][2][2]uint32:
c, t = gltf.ComponentUint, gltf.AccessorMat2
case [][3][3]uint32, [3][3]uint32:
case [][3][3]uint32:
c, t = gltf.ComponentUint, gltf.AccessorMat3
case [][4][4]uint32, [4][4]uint32:
case [][4][4]uint32:
c, t = gltf.ComponentUint, gltf.AccessorMat4
case []float32, float32:
case []float32:
c, t = gltf.ComponentFloat, gltf.AccessorScalar
case [][2]float32, [2]float32:
case [][2]float32:
c, t = gltf.ComponentFloat, gltf.AccessorVec2
case []gltf.RGB, gltf.RGB, [][3]float32, [3]float32:
case [][3]float32:
c, t = gltf.ComponentFloat, gltf.AccessorVec3
case []gltf.RGBA, gltf.RGBA, [][4]float32, [4]float32:
case [][4]float32:
c, t = gltf.ComponentFloat, gltf.AccessorVec4
case [][2][2]float32, [2][2]float32:
case [][2][2]float32:
c, t = gltf.ComponentFloat, gltf.AccessorMat2
case [][3][3]float32, [3][3]float32:
case [][3][3]float32:
c, t = gltf.ComponentFloat, gltf.AccessorMat3
case [][4][4]float32, [4][4]float32:
case [][4][4]float32:
c, t = gltf.ComponentFloat, gltf.AccessorMat4
default:
length = 0
panic(fmt.Sprintf("go3mf: binary.Type expecting a glTF supported type but got %s", v.Kind()))
}
return
}

0 comments on commit eb539ba

Please sign in to comment.