package main // This reads obj files? import ( "bufio" "fmt" "io" "log" "strings" ) type Vec3f struct { X, Y, Z float32 } type Vec2i struct { X, Y int } type Facef [3]Vec3f type ObjModel struct { Vertices []Vec3f Faces []Facef } // Parse an obj file at the given reader. Only handles v and f right now func ParseObj(reader io.Reader) (*ObjModel, error) { result := ObjModel{ Vertices: make([]Vec3f, 0), Faces: make([]Facef, 0), } breader := bufio.NewReader(reader) done := false for !done { // Scan a line line, err := breader.ReadString('\n') if err != nil { if err == io.EOF { done = true } else { log.Printf("NOT EOF ERR?") return nil, err } } line = strings.Trim(line, " \t\n\r") if len(line) == 0 { continue } // Find the first "item", whatever that is. This also gets rid of comments // since we just don't use lines that start with # (no handler var t string _, err = fmt.Sscan(line, &t) if err != nil { log.Printf("SSCANF ERR") return nil, err } line = line[len(t):] if t == "v" { // Read a vertex, should be just three floats var vertex Vec3f _, err := fmt.Sscan(line, &vertex.X, &vertex.Y, &vertex.Z) if err != nil { return nil, err } result.Vertices = append(result.Vertices, vertex) } else if t == "f" { // Read a face; in our example, it's always three sets. // For THIS example, we throw away those other values var face Facef var vi [3]int var ti int _, err := fmt.Sscanf(line, "%d/%d/%d %d/%d/%d %d/%d/%d", &vi[0], &ti, &ti, &vi[1], &ti, &ti, &vi[2], &ti, &ti) if err != nil { return nil, err } for i := range 3 { if vi[i] > len(result.Vertices) || vi[i] < 1 { return nil, fmt.Errorf("Face vertex index out of bounds: %d", vi[i]) } face[i] = result.Vertices[vi[i]-1] } result.Faces = append(result.Faces, face) } } return &result, nil }