package hrend // This reads obj files? import ( "bufio" "fmt" "io" "log" "strings" ) // A single vertex generally has multiple items associated with it // when it's part of a face. type Vertex struct { Pos Vec3f Tex Vec3f } type Facef [3]Vertex type ObjModel struct { Vertices []Vec3f VTexture []Vec3f Faces []Facef } func (o *ObjModel) ClearCachedVertexInfo() { o.Vertices = nil o.VTexture = nil } // 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), VTexture: 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 v Vec3f _, err := fmt.Sscan(line, &v.X, &v.Y, &v.Z) if err != nil { return nil, err } result.Vertices = append(result.Vertices, v) } else if t == "vt" { // Read a vertex tex coord, should be just three floats too var vt Vec3f _, err := fmt.Sscan(line, &vt.X, &vt.Y, &vt.Z) if err != nil { return nil, err } result.VTexture = append(result.VTexture, vt) } 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 vti [3]int var ti int _, err := fmt.Sscanf(line, "%d/%d/%d %d/%d/%d %d/%d/%d", &vi[0], &vti[0], &ti, &vi[1], &vti[1], &ti, &vi[2], &vti[2], &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].Pos = result.Vertices[vi[i]-1] if vti[i] > len(result.VTexture) || vti[i] < 1 { return nil, fmt.Errorf("Face vertex texture index out of bounds: %d", vti[i]) } face[i].Tex = result.VTexture[vti[i]-1] } result.Faces = append(result.Faces, face) } } log.Printf("Obj had %d vertices, %d faces", len(result.Vertices), len(result.Faces)) return &result, nil }