package exporter import ( "bytes" "fmt" "image" "image/png" "log" "os" _ "github.com/ftrvxmtrx/tga" "github.com/qmuntal/gltf" "github.com/qmuntal/gltf/modeler" "git.influ.su/artmares/digglestool/pkg/threedb" ) type Model struct { doc *gltf.Document materialMap map[uint16]int } func (m *Model) Generate(model *threedb.Model, cache *Cache[*CacheItem], meshIndexes ...int) (*gltf.Document, error) { m.doc = gltf.NewDocument() m.doc.Scenes = []*gltf.Scene{} m.materialMap = make(map[uint16]int) log.Println("Generate use mesh indexes", len(meshIndexes)) for i, meshIndex := range meshIndexes { mesh := model.Meshes[meshIndex] var nodeIndexes []int for index, link := range mesh.Links { materialIndex, err := m.materialIndex(model, cache, link.Material) if err != nil { return nil, err } verticesIndex := m.generateVertices(model.Points[link.Points]) textureCoordIndex := m.generateTextureCoordinate(model.TextureCoordinates[link.TextureCoordinates]) trianglesIndex := modeler.WriteAccessor(m.doc, gltf.TargetArrayBuffer, model.Triangles[link.Triangles]) m.doc.Meshes = append(m.doc.Meshes, &gltf.Mesh{ Name: fmt.Sprintf("%s-%d-%d", model.Name, i, index), Primitives: []*gltf.Primitive{{ Attributes: gltf.PrimitiveAttributes{ gltf.POSITION: verticesIndex, gltf.TEXCOORD_0: textureCoordIndex, }, Indices: gltf.Index(trianglesIndex), Material: gltf.Index(materialIndex), }}, }) nodeIndexes = append(nodeIndexes, len(m.doc.Nodes)) m.doc.Nodes = append(m.doc.Nodes, &gltf.Node{ Mesh: gltf.Index(len(m.doc.Meshes) - 1), }) } m.doc.Scenes = append(m.doc.Scenes, &gltf.Scene{ Name: fmt.Sprintf("Root Scene-%d", meshIndex), Nodes: nodeIndexes, }) } m.doc.Samplers = []*gltf.Sampler{{}} return m.doc, nil } func (m *Model) generateVertices(vectors []threedb.Vector) int { var vertices [][3]float32 for _, vector := range vectors { vector = vector.Transform(100) vertices = append(vertices, vector.Normalize()) } return modeler.WriteAccessor(m.doc, gltf.TargetElementArrayBuffer, vertices) } func (m *Model) generateTextureCoordinate(coordinates []threedb.Coordinate) int { var coords [][2]float32 for _, coordinate := range coordinates { coords = append(coords, coordinate) } return modeler.WriteAccessor(m.doc, gltf.TargetArrayBuffer, coords) } func (m *Model) materialIndex(model *threedb.Model, cache *Cache[*CacheItem], meshMaterialIndex uint16) (int, error) { //logger, logPutter := helpers.NewBuffer() //defer func() { // logPutter(logger) //}() materialIndex, ok := m.materialMap[meshMaterialIndex] //logger.WriteString(fmt.Sprintf("Try find material index %d\n", meshMaterialIndex)) if !ok { //logger.WriteString(fmt.Sprintf("Material index %d not found\n", meshMaterialIndex)) material := model.Materials[meshMaterialIndex] item, ok := cache.Get(material.Name) if !ok { return 0, nil } //logger.WriteString(fmt.Sprintf("Try found material name %s\n", material.Name)) if item.Bytes == nil { //logger.WriteString(fmt.Sprintf("Material name %s not found in cache\n", material.Name)) f, err := os.Open(item.Path) if err != nil { return 0, err } defer f.Close() img, _, err := image.Decode(f) if err != nil { return 0, err } item.Bytes = &bytes.Buffer{} if err = png.Encode(item.Bytes, img); err != nil { return 0, err } cache.Set(material.Name, item) } //log.Printf("material index: %d, material name: %s, data: %d", meshMaterialIndex, material.Name, len(data)) imageIndex, err := modeler.WriteImage(m.doc, material.Name, "image/png", item.Bytes) if err != nil { return 0, err } m.doc.Textures = append(m.doc.Textures, &gltf.Texture{ Name: material.Name, Sampler: gltf.Index(0), Source: gltf.Index(imageIndex), }) materialIndex = len(m.doc.Materials) m.doc.Materials = append(m.doc.Materials, &gltf.Material{ Name: material.Name, AlphaMode: gltf.AlphaOpaque, AlphaCutoff: gltf.Float(0.5), PBRMetallicRoughness: &gltf.PBRMetallicRoughness{ BaseColorTexture: &gltf.TextureInfo{Index: imageIndex}, BaseColorFactor: &[4]float64{0.8, 0.8, 0.8, 1}, MetallicFactor: gltf.Float(0.1), RoughnessFactor: gltf.Float(0.99), }, }) m.materialMap[meshMaterialIndex] = materialIndex } //log.Println(logger.String()) return materialIndex, nil }