|
|
@@ -27,6 +27,7 @@ import (
|
|
|
"github.com/g3n/engine/material"
|
|
|
"github.com/g3n/engine/math32"
|
|
|
"github.com/g3n/engine/texture"
|
|
|
+ "github.com/g3n/engine/animation"
|
|
|
)
|
|
|
|
|
|
// ParseJSON parses the glTF data from the specified JSON file
|
|
|
@@ -78,14 +79,14 @@ func ParseBin(filename string) (*GLTF, error) {
|
|
|
// and returns a pointer to the parsed structure
|
|
|
func ParseBinReader(r io.Reader, path string) (*GLTF, error) {
|
|
|
|
|
|
- // Reads header
|
|
|
+ // Read header
|
|
|
var header GLBHeader
|
|
|
err := binary.Read(r, binary.LittleEndian, &header)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- // Checks magic and version
|
|
|
+ // Check magic and version
|
|
|
if header.Magic != GLBMagic {
|
|
|
return nil, fmt.Errorf("Invalid GLB Magic field")
|
|
|
}
|
|
|
@@ -149,6 +150,8 @@ func readChunk(r io.Reader, chunkType uint32) ([]byte, error) {
|
|
|
// the specified scene index from the GLTF Scenes array
|
|
|
func (g *GLTF) NewScene(si int) (core.INode, error) {
|
|
|
|
|
|
+ log.Debug("Creating Scene %d", si)
|
|
|
+
|
|
|
// Check if provided scene index is valid
|
|
|
if si < 0 || si >= len(g.Scenes) {
|
|
|
return nil, fmt.Errorf("invalid scene index")
|
|
|
@@ -157,8 +160,8 @@ func (g *GLTF) NewScene(si int) (core.INode, error) {
|
|
|
|
|
|
scene := core.NewNode()
|
|
|
scene.SetName(s.Name)
|
|
|
- for i := 0; i < len(s.Nodes); i++ {
|
|
|
- child, err := g.NewNode(i)
|
|
|
+ for _, ni := range s.Nodes {
|
|
|
+ child, err := g.NewNode(ni)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
@@ -171,69 +174,121 @@ func (g *GLTF) NewScene(si int) (core.INode, error) {
|
|
|
// in the decoded GLTF Nodes array.
|
|
|
func (g *GLTF) NewNode(i int) (core.INode, error) {
|
|
|
|
|
|
+ log.Debug("Creating Node %d", i)
|
|
|
+
|
|
|
var in core.INode
|
|
|
var err error
|
|
|
- node := g.Nodes[i]
|
|
|
+ nodeData := g.Nodes[i]
|
|
|
|
|
|
// Check if the node is a Mesh (triangles, lines, etc...)
|
|
|
- if node.Mesh != nil {
|
|
|
- in, err = g.loadMesh(*node.Mesh)
|
|
|
+ if nodeData.Mesh != nil {
|
|
|
+ in, err = g.loadMesh(*nodeData.Mesh)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
// Check if the node is Camera
|
|
|
- } else if node.Camera != nil {
|
|
|
- in, err = g.loadCamera(*node.Camera)
|
|
|
+ } else if nodeData.Camera != nil {
|
|
|
+ in, err = g.loadCamera(*nodeData.Camera)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
// Other cases, return empty node
|
|
|
} else {
|
|
|
+ log.Debug("Empty Node")
|
|
|
in = core.NewNode()
|
|
|
}
|
|
|
|
|
|
+ // Cache inode in nodeData
|
|
|
+ g.Nodes[i].node = in
|
|
|
+
|
|
|
// Get *core.Node from core.INode
|
|
|
- n := in.GetNode()
|
|
|
- n.SetName(node.Name)
|
|
|
+ node := in.GetNode()
|
|
|
+ node.SetName(nodeData.Name)
|
|
|
|
|
|
// If defined, set node local transformation matrix
|
|
|
- if node.Matrix != nil {
|
|
|
- n.SetMatrix((*math32.Matrix4)(node.Matrix))
|
|
|
+ if nodeData.Matrix != nil {
|
|
|
+ node.SetMatrix((*math32.Matrix4)(nodeData.Matrix))
|
|
|
// Otherwise, check rotation, scale and translation fields
|
|
|
} else {
|
|
|
// Rotation quaternion
|
|
|
- if node.Rotation != nil {
|
|
|
- log.Error("Rotation:%v", node.Translation)
|
|
|
- n.SetQuaternion(node.Rotation[0], node.Rotation[1], node.Rotation[2], node.Rotation[3])
|
|
|
+ if nodeData.Rotation != nil {
|
|
|
+ node.SetQuaternion(nodeData.Rotation[0], nodeData.Rotation[1], nodeData.Rotation[2], nodeData.Rotation[3])
|
|
|
}
|
|
|
// Scale
|
|
|
- if node.Scale != nil {
|
|
|
- log.Error("Scale:%v", node.Translation)
|
|
|
- n.SetScale(node.Scale[0], node.Scale[1], node.Scale[2])
|
|
|
+ if nodeData.Scale != nil {
|
|
|
+ node.SetScale(nodeData.Scale[0], nodeData.Scale[1], nodeData.Scale[2])
|
|
|
}
|
|
|
// Translation
|
|
|
- if node.Translation != nil {
|
|
|
- log.Error("Translation:%v", node.Translation)
|
|
|
- n.SetPosition(node.Translation[0], node.Translation[1], node.Translation[2])
|
|
|
+ if nodeData.Translation != nil {
|
|
|
+ node.SetPosition(nodeData.Translation[0], nodeData.Translation[1], nodeData.Translation[2])
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- // Recursively load node children and add them to the parent
|
|
|
- for _, ci := range node.Children {
|
|
|
+ // Recursively load node children and add them to the parent
|
|
|
+ for _, ci := range nodeData.Children {
|
|
|
child, err := g.NewNode(ci)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- n.Add(child)
|
|
|
+ node.Add(child)
|
|
|
}
|
|
|
|
|
|
return in, nil
|
|
|
}
|
|
|
|
|
|
+// NewAnimation creates a parent Node which contains all nodes contained by
|
|
|
+// the specified scene index from the GLTF Scenes array
|
|
|
+func (g *GLTF) NewAnimation(i int) (*animation.Animation, error) {
|
|
|
+
|
|
|
+ log.Debug("Creating Animation %d", i)
|
|
|
+
|
|
|
+ // Check if provided scene index is valid
|
|
|
+ if i < 0 || i >= len(g.Animations) {
|
|
|
+ return nil, fmt.Errorf("invalid animation index")
|
|
|
+ }
|
|
|
+ a := g.Animations[i]
|
|
|
+
|
|
|
+ anim := animation.NewAnimation()
|
|
|
+ anim.SetName(a.Name)
|
|
|
+ for i := 0; i < len(a.Channels); i++ {
|
|
|
+
|
|
|
+ chData := a.Channels[i]
|
|
|
+ target := chData.Target
|
|
|
+ sampler := a.Samplers[chData.Sampler]
|
|
|
+ node := g.Nodes[target.Node].node
|
|
|
+ // TODO Instantiate node if not exists ?
|
|
|
+
|
|
|
+ var ch animation.IChannel
|
|
|
+ if target.Path == "translation" {
|
|
|
+ ch = animation.NewPositionChannel(node)
|
|
|
+ } else if target.Path == "rotation" {
|
|
|
+ ch = animation.NewRotationChannel(node)
|
|
|
+ } else if target.Path == "scale" {
|
|
|
+ ch = animation.NewScaleChannel(node)
|
|
|
+ }
|
|
|
+
|
|
|
+ keyframes, err := g.loadAccessorF32(sampler.Input, []string{}, []int{})
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ values, err := g.loadAccessorF32(sampler.Output, []string{}, []int{})
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+ ch.SetBuffers(keyframes, values)
|
|
|
+ ch.SetInterpolationType(animation.InterpolationType(sampler.Interpolation))
|
|
|
+ //ch.SetInterpolationType(animation.STEP)//animation.InterpolationType(sampler.Interpolation))
|
|
|
+ anim.AddChannel(ch)
|
|
|
+ }
|
|
|
+ return anim, nil
|
|
|
+}
|
|
|
+
|
|
|
// loadCamera creates and returns a Camera Node
|
|
|
// from the specified GLTF.Cameras index
|
|
|
func (g *GLTF) loadCamera(ci int) (core.INode, error) {
|
|
|
|
|
|
+ log.Debug("Loading Camera %d", ci)
|
|
|
+
|
|
|
camDesc := g.Cameras[ci]
|
|
|
if camDesc.Type == "perspective" {
|
|
|
desc := camDesc.Perspective
|
|
|
@@ -264,6 +319,8 @@ func (g *GLTF) loadCamera(ci int) (core.INode, error) {
|
|
|
// from the specified GLTF Mesh index
|
|
|
func (g *GLTF) loadMesh(mi int) (core.INode, error) {
|
|
|
|
|
|
+ log.Debug("Loading Mesh %d", mi)
|
|
|
+
|
|
|
var err error
|
|
|
m := g.Meshes[mi]
|
|
|
|
|
|
@@ -313,38 +370,51 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
|
|
|
// }
|
|
|
//}
|
|
|
if name == "POSITION" {
|
|
|
- ppos, err := g.loadVec3(aci)
|
|
|
+ ppos, err := g.loadPositions(aci)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- vbo := gls.NewVBO()
|
|
|
- vbo.AddAttrib("VertexPosition", 3)
|
|
|
- vbo.SetBuffer(ppos)
|
|
|
+ vbo := gls.NewVBO().AddAttrib("VertexPosition", 3).SetBuffer(ppos)
|
|
|
geom.AddVBO(vbo)
|
|
|
continue
|
|
|
}
|
|
|
if name == "NORMAL" {
|
|
|
- pnorms, err := g.loadVec3(aci)
|
|
|
+ pnorms, err := g.loadNormals(aci)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- vbo := gls.NewVBO()
|
|
|
- vbo.AddAttrib("VertexNormal", 3)
|
|
|
- vbo.SetBuffer(pnorms)
|
|
|
+ vbo := gls.NewVBO().AddAttrib("VertexNormal", 3).SetBuffer(pnorms)
|
|
|
geom.AddVBO(vbo)
|
|
|
continue
|
|
|
}
|
|
|
- if name == "TEXCOORD_0" {
|
|
|
- puvs, err := g.loadVec2(aci)
|
|
|
+ if name == "TANGENT" {
|
|
|
+ // TODO
|
|
|
+ log.Error("TANGENT attribute not supported yet.")
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ attrib := strings.Split(name, "_")
|
|
|
+ semantic := attrib[0]
|
|
|
+ //set := attrib[1] TODO
|
|
|
+
|
|
|
+ if semantic == "TEXCOORD" {
|
|
|
+ puvs, err := g.loadTexcoords(aci)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
- vbo := gls.NewVBO()
|
|
|
- vbo.AddAttrib("VertexTexcoord", 2)
|
|
|
- vbo.SetBuffer(puvs)
|
|
|
+ vbo := gls.NewVBO().AddAttrib("VertexTexcoord", 2).SetBuffer(puvs)
|
|
|
geom.AddVBO(vbo)
|
|
|
continue
|
|
|
}
|
|
|
+ if semantic == "COLOR" {
|
|
|
+ // TODO
|
|
|
+ }
|
|
|
+ if semantic == "JOINTS" {
|
|
|
+ // TODO
|
|
|
+ }
|
|
|
+ if semantic == "WEIGHTS" {
|
|
|
+ // TODO
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Creates Geometry and add attribute VBO
|
|
|
@@ -352,11 +422,11 @@ func (g *GLTF) loadMesh(mi int) (core.INode, error) {
|
|
|
geom.SetIndices(indices)
|
|
|
}
|
|
|
|
|
|
- //log.Error("positions:%v", positions)
|
|
|
- //log.Error("indices..:%v", indices)
|
|
|
- //log.Error("normals..:%v", normals)
|
|
|
- //log.Error("uvs0.....:%v", uvs0)
|
|
|
- //log.Error("VBUF size in number of floats:%v", len(vbuf))
|
|
|
+ //log.Debug("positions:%v", positions)
|
|
|
+ //log.Debug("indices..:%v", indices)
|
|
|
+ //log.Debug("normals..:%v", normals)
|
|
|
+ //log.Debug("uvs0.....:%v", uvs0)
|
|
|
+ //log.Debug("VBUF size in number of floats:%v", len(vbuf))
|
|
|
|
|
|
// Default mode is 4 (TRIANGLES)
|
|
|
mode := TRIANGLES
|
|
|
@@ -400,10 +470,10 @@ func (g *GLTF) newDefaultMaterial() material.IMaterial {
|
|
|
// loadMaterials loads the material specified by the material index
|
|
|
func (g *GLTF) loadMaterial(mi int) (material.IMaterial, error) {
|
|
|
|
|
|
- mat := g.Materials[mi]
|
|
|
+ matData := g.Materials[mi]
|
|
|
// Checks for material extensions
|
|
|
- if mat.Extensions != nil {
|
|
|
- for ext, v := range mat.Extensions {
|
|
|
+ if matData.Extensions != nil {
|
|
|
+ for ext, v := range matData.Extensions {
|
|
|
if ext == "KHR_materials_common" {
|
|
|
return g.loadMaterialCommon(v)
|
|
|
} else {
|
|
|
@@ -413,7 +483,7 @@ func (g *GLTF) loadMaterial(mi int) (material.IMaterial, error) {
|
|
|
return nil, fmt.Errorf("Empty material extensions")
|
|
|
// Material should be PBR
|
|
|
} else {
|
|
|
- return g.loadMaterialPBR(&mat)
|
|
|
+ return g.loadMaterialPBR(&matData)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -435,37 +505,43 @@ func (g *GLTF) loadTexture(texi int) (*texture.Texture2D, error) {
|
|
|
tex := texture.NewTexture2DFromRGBA(img)
|
|
|
|
|
|
// Get sampler and apply texture parameters
|
|
|
- samp := g.Samplers[texDesc.Sampler]
|
|
|
+ if texDesc.Sampler != nil {
|
|
|
+ sampler := g.Samplers[*texDesc.Sampler]
|
|
|
+ g.applySampler(sampler, tex)
|
|
|
+ }
|
|
|
+
|
|
|
+ return tex, nil
|
|
|
+}
|
|
|
+
|
|
|
+func (g *GLTF) applySampler(sampler Sampler, tex *texture.Texture2D) {
|
|
|
|
|
|
// Magnification filter
|
|
|
magFilter := gls.NEAREST
|
|
|
- if samp.MagFilter != nil {
|
|
|
- magFilter = *samp.MagFilter
|
|
|
+ if sampler.MagFilter != nil {
|
|
|
+ magFilter = *sampler.MagFilter
|
|
|
}
|
|
|
tex.SetMagFilter(uint32(magFilter))
|
|
|
|
|
|
// Minification filter
|
|
|
minFilter := gls.NEAREST
|
|
|
- if samp.MinFilter != nil {
|
|
|
- minFilter = *samp.MinFilter
|
|
|
+ if sampler.MinFilter != nil {
|
|
|
+ minFilter = *sampler.MinFilter
|
|
|
}
|
|
|
tex.SetMinFilter(uint32(minFilter))
|
|
|
|
|
|
// S coordinate wrapping mode
|
|
|
wrapS := gls.REPEAT
|
|
|
- if samp.WrapS != nil {
|
|
|
- wrapS = *samp.WrapS
|
|
|
+ if sampler.WrapS != nil {
|
|
|
+ wrapS = *sampler.WrapS
|
|
|
}
|
|
|
tex.SetWrapS(uint32(wrapS))
|
|
|
|
|
|
// T coordinate wrapping mode
|
|
|
wrapT := gls.REPEAT
|
|
|
- if samp.WrapT != nil {
|
|
|
- wrapT = *samp.WrapT
|
|
|
+ if sampler.WrapT != nil {
|
|
|
+ wrapT = *sampler.WrapT
|
|
|
}
|
|
|
tex.SetWrapT(uint32(wrapT))
|
|
|
-
|
|
|
- return tex, nil
|
|
|
}
|
|
|
|
|
|
// loadImage loads the image specified by the index of GLTF.Images
|
|
|
@@ -524,45 +600,57 @@ func (g *GLTF) loadImage(ii int) (*image.RGBA, error) {
|
|
|
return rgba, nil
|
|
|
}
|
|
|
|
|
|
-// loadVec3 load array of float32 values from the specified accessor index.
|
|
|
-// The acesssor must have type of VEC3 and component type of FLOAT
|
|
|
-func (g *GLTF) loadVec3(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+// loadAccessorData loads the indices array specified by the Accessor index.
|
|
|
+func (g *GLTF) loadAccessorU32(ai int, validTypes []string, validComponentTypes []int) (math32.ArrayU32, error) {
|
|
|
|
|
|
// Get Accessor for the specified index
|
|
|
ac := g.Accessors[ai]
|
|
|
if ac.BufferView == nil {
|
|
|
- return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED")
|
|
|
+ return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED YET") // TODO
|
|
|
}
|
|
|
|
|
|
- // Checks acessor ComponentType
|
|
|
- if ac.ComponentType != FLOAT {
|
|
|
- return nil, fmt.Errorf("Accessor.ComponentType != FLOAT NOT SUPPORTED")
|
|
|
- }
|
|
|
-
|
|
|
- // Checks acessor Type
|
|
|
- if ac.Type != VEC3 {
|
|
|
- return nil, fmt.Errorf("Accessor.ComponentType != VEC3 NOT SUPPORTED")
|
|
|
+ // Validate type and component type
|
|
|
+ err := g.validateAccessor(ac, validTypes, validComponentTypes)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
|
|
|
- // Loads data from associated BufferView
|
|
|
- data, err := g.loadBufferView(*ac.BufferView)
|
|
|
+ // Load bytes
|
|
|
+ data, err := g.loadAccessorBytes(ac)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- // Accessor offset into BufferView
|
|
|
- offset := 0
|
|
|
- if ac.ByteOffset != nil {
|
|
|
- offset = *ac.ByteOffset
|
|
|
+ // If component is UNSIGNED_INT nothing to do
|
|
|
+ if ac.ComponentType == UNSIGNED_INT {
|
|
|
+ arr := (*[1 << 30]uint32)(unsafe.Pointer(&data[0]))[:ac.Count]
|
|
|
+ return math32.ArrayU32(arr), nil
|
|
|
}
|
|
|
- data = data[offset:]
|
|
|
|
|
|
- arr := (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:ac.Count*3]
|
|
|
- return math32.ArrayF32(arr), nil
|
|
|
+ // Converts UNSIGNED_SHORT to UNSIGNED_INT
|
|
|
+ if ac.ComponentType == UNSIGNED_SHORT {
|
|
|
+ out := math32.NewArrayU32(ac.Count, ac.Count)
|
|
|
+ for i := 0; i < ac.Count; i++ {
|
|
|
+ out[i] = uint32(data[i*2]) + uint32(data[i*2+1])*256
|
|
|
+ }
|
|
|
+ return out, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ // Converts UNSIGNED_BYTE indices to UNSIGNED_INT
|
|
|
+ if ac.ComponentType == UNSIGNED_BYTE {
|
|
|
+ out := math32.NewArrayU32(ac.Count, ac.Count)
|
|
|
+ for i := 0; i < ac.Count; i++ {
|
|
|
+ out[i] = uint32(data[i])
|
|
|
+ }
|
|
|
+ return out, nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil, fmt.Errorf("Unsupported Accessor ComponentType:%v", ac.ComponentType)
|
|
|
}
|
|
|
|
|
|
-// loadVec2 load array of Vector2 from the specified accessor index
|
|
|
-func (g *GLTF) loadVec2(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+func (g *GLTF) loadAccessorF32(ai int, validTypes []string, validComponentTypes []int) (math32.ArrayF32, error) {
|
|
|
|
|
|
// Get Accessor for the specified index
|
|
|
ac := g.Accessors[ai]
|
|
|
@@ -570,44 +658,54 @@ func (g *GLTF) loadVec2(ai int) (math32.ArrayF32, error) {
|
|
|
return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED")
|
|
|
}
|
|
|
|
|
|
- // Checks acessor ComponentType
|
|
|
- if ac.ComponentType != FLOAT {
|
|
|
- return nil, fmt.Errorf("Accessor.ComponentType != FLOAT NOT SUPPORTED")
|
|
|
- }
|
|
|
-
|
|
|
- // Checks acessor Type
|
|
|
- if ac.Type != VEC2 {
|
|
|
- return nil, fmt.Errorf("Accessor.ComponentType != VEC2 NOT SUPPORTED")
|
|
|
- }
|
|
|
-
|
|
|
- // Loads data from associated BufferView
|
|
|
- data, err := g.loadBufferView(*ac.BufferView)
|
|
|
+ // Validate type and component type
|
|
|
+ err := g.validateAccessor(ac, validTypes, validComponentTypes)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
- // Accessor offset into BufferView
|
|
|
- offset := 0
|
|
|
- if ac.ByteOffset != nil {
|
|
|
- offset = *ac.ByteOffset
|
|
|
+ // Load bytes
|
|
|
+ data, err := g.loadAccessorBytes(ac)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
}
|
|
|
- data = data[offset:]
|
|
|
|
|
|
- arr := (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:ac.Count*2]
|
|
|
+ arr := (*[1 << 30]float32)(unsafe.Pointer(&data[0]))[:ac.Count*TypeSizes[ac.Type]]
|
|
|
return math32.ArrayF32(arr), nil
|
|
|
}
|
|
|
|
|
|
-// loadIndices load the indices array specified by the Accessor index.
|
|
|
-func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
|
|
|
+// TODO
|
|
|
+func (g *GLTF) validateAccessor(ac Accessor, validTypes []string, validComponentTypes []int) error {
|
|
|
+
|
|
|
+ // Check if points to a valid buffer view
|
|
|
+ //if ac.BufferView == nil {
|
|
|
+ // return fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED")
|
|
|
+ //}
|
|
|
+ //
|
|
|
+ //// Check accessor ComponentType
|
|
|
+ //if ac.ComponentType != FLOAT {
|
|
|
+ // return fmt.Errorf("Accessor.ComponentType != FLOAT NOT SUPPORTED")
|
|
|
+ //}
|
|
|
+ //
|
|
|
+ //// Check accessor Type
|
|
|
+ //if ac.Type != VEC3 {
|
|
|
+ // return fmt.Errorf("Accessor.ComponentType != VEC3 NOT SUPPORTED")
|
|
|
+ //}
|
|
|
|
|
|
- // Get Accessor for the specified index
|
|
|
- ac := g.Accessors[ai]
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// loadAccessorBytes
|
|
|
+func (g *GLTF) loadAccessorBytes(ac Accessor) ([]byte, error) {
|
|
|
+
|
|
|
+ // Get the Accessor's BufferView
|
|
|
if ac.BufferView == nil {
|
|
|
- return nil, fmt.Errorf("Accessor.BufferView == nil NOT SUPPORTED YET")
|
|
|
+ return nil, fmt.Errorf("Accessor has nil BufferView") // TODO
|
|
|
}
|
|
|
+ bv := g.BufferViews[*ac.BufferView]
|
|
|
|
|
|
- // Loads indices data from associated BufferView
|
|
|
- data, err := g.loadBufferView(*ac.BufferView)
|
|
|
+ // Loads data from associated BufferView
|
|
|
+ data, err := g.loadBufferView(bv)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
@@ -619,30 +717,20 @@ func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
|
|
|
}
|
|
|
data = data[offset:]
|
|
|
|
|
|
- // If index component is UNSIGNED_INT nothing to do
|
|
|
- if ac.ComponentType == UNSIGNED_INT {
|
|
|
- arr := (*[1 << 30]uint32)(unsafe.Pointer(&data[0]))[:ac.Count]
|
|
|
- return math32.ArrayU32(arr), nil
|
|
|
- }
|
|
|
+ // Check if interleaved and de-interleave if necessary
|
|
|
|
|
|
- // Converts UNSIGNED_SHORT indices to UNSIGNED_INT
|
|
|
- if ac.ComponentType == UNSIGNED_SHORT {
|
|
|
- indices := math32.NewArrayU32(ac.Count, ac.Count)
|
|
|
- for i := 0; i < ac.Count; i++ {
|
|
|
- indices[i] = uint32(data[i*2]) + uint32(data[i*2+1])*256
|
|
|
- }
|
|
|
- return indices, nil
|
|
|
- }
|
|
|
+ // Calculate the size in bytes of a complete attribute
|
|
|
+ itemSize := TypeSizes[ac.Type]
|
|
|
+ itemBytes := int(gls.FloatSize) * itemSize
|
|
|
|
|
|
- // Converts UNSIGNED_BYTE indices to UNSIGNED_INT
|
|
|
- if ac.ComponentType == UNSIGNED_BYTE {
|
|
|
- indices := math32.NewArrayU32(ac.Count, ac.Count)
|
|
|
- for i := 0; i < ac.Count; i++ {
|
|
|
- indices[i] = uint32(data[i])
|
|
|
- }
|
|
|
- return indices, nil
|
|
|
+ // If the BufferView stride is equal to the item size, the buffer is not interleaved
|
|
|
+ if (bv.ByteStride != nil) && (*bv.ByteStride != itemBytes) {
|
|
|
+ // BufferView data is interleaved, de-interleave
|
|
|
+ // TODO
|
|
|
+ log.Error("DATA IS INTERLEAVED - NOT SUPPORTED YET!")
|
|
|
}
|
|
|
- return nil, fmt.Errorf("Unsupported Accessor ComponentType:%v", ac.ComponentType)
|
|
|
+
|
|
|
+ return data, nil
|
|
|
}
|
|
|
|
|
|
// isInterleaves checks if the BufferView used by the specified Accessor index is
|
|
|
@@ -670,20 +758,71 @@ func (g *GLTF) isInterleaved(aci int) bool {
|
|
|
return true
|
|
|
}
|
|
|
|
|
|
-// loadBufferView loads and returns a byte slice with data from the specified
|
|
|
-// BufferView index
|
|
|
-func (g *GLTF) loadBufferView(bvi int) ([]byte, error) {
|
|
|
+// loadPosition load array of float32 values from the specified accessor index.
|
|
|
+// The acesssor must have type of VEC3 and component type of FLOAT
|
|
|
+func (g *GLTF) loadPositions(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC3}, []int{FLOAT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadNormals(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC3}, []int{FLOAT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadTangents(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC4}, []int{FLOAT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadTexcoords(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC3}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadColors(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC3, VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadJoints(ai int) (math32.ArrayF32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC4}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadWeights(ai int) (math32.ArrayF32, error) {
|
|
|
|
|
|
- bv := g.BufferViews[bvi]
|
|
|
+ return g.loadAccessorF32(ai, []string{VEC4}, []int{FLOAT, UNSIGNED_BYTE, UNSIGNED_SHORT})
|
|
|
+}
|
|
|
+
|
|
|
+//
|
|
|
+func (g *GLTF) loadIndices(ai int) (math32.ArrayU32, error) {
|
|
|
+
|
|
|
+ return g.loadAccessorU32(ai, []string{SCALAR}, []int{UNSIGNED_BYTE, UNSIGNED_SHORT, UNSIGNED_INT}) // TODO check that it's ELEMENT_ARRAY_BUFFER
|
|
|
+}
|
|
|
+
|
|
|
+// loadBufferView loads and returns a byte slice with data from the specified BufferView index
|
|
|
+func (g *GLTF) loadBufferView(bv BufferView) ([]byte, error) {
|
|
|
+
|
|
|
+ // Load buffer view buffer
|
|
|
buf, err := g.loadBuffer(bv.Buffer)
|
|
|
if err != nil {
|
|
|
return nil, err
|
|
|
}
|
|
|
|
|
|
+ // Establish offset
|
|
|
offset := 0
|
|
|
if bv.ByteOffset != nil {
|
|
|
offset = *bv.ByteOffset
|
|
|
}
|
|
|
+
|
|
|
+ // Compute and return offset slice
|
|
|
return buf[offset : offset+bv.ByteLength], nil
|
|
|
}
|
|
|
|
|
|
@@ -691,13 +830,13 @@ func (g *GLTF) loadBufferView(bvi int) ([]byte, error) {
|
|
|
func (g *GLTF) loadBuffer(bi int) ([]byte, error) {
|
|
|
|
|
|
buf := &g.Buffers[bi]
|
|
|
- // If Buffer URI uses the chunk data field
|
|
|
+ // If Buffer URI use the chunk data field
|
|
|
if buf.Uri == "" {
|
|
|
return g.data, nil
|
|
|
}
|
|
|
|
|
|
// If buffer already loaded:
|
|
|
- log.Error("loadBuffer cache:%v", len(buf.data))
|
|
|
+ log.Debug("loadBuffer cache:%v", len(buf.data))
|
|
|
if len(buf.data) > 0 {
|
|
|
return buf.data, nil
|
|
|
}
|
|
|
@@ -712,7 +851,7 @@ func (g *GLTF) loadBuffer(bi int) ([]byte, error) {
|
|
|
}
|
|
|
// Loads external buffer file
|
|
|
} else {
|
|
|
- log.Error("loadBuffer: loading file")
|
|
|
+ log.Debug("loadBuffer: loading file")
|
|
|
// Try to load buffer from file
|
|
|
fpath := filepath.Join(g.path, buf.Uri)
|
|
|
f, err := os.Open(fpath)
|
|
|
@@ -731,7 +870,7 @@ func (g *GLTF) loadBuffer(bi int) ([]byte, error) {
|
|
|
}
|
|
|
// Cache buffer data
|
|
|
buf.data = data
|
|
|
- log.Error("cache data:%v", len(buf.data))
|
|
|
+ log.Debug("cache data:%v", len(buf.data))
|
|
|
return data, nil
|
|
|
}
|
|
|
|