package geometry import ( "bufio" "fmt" "os" "strconv" "strings" "github.com/go-gl/gl/v4.6-core/gl" ) // attributes: // position 3 * float // normal 3 * float // texture coordinates 2 * float type Geometry struct { vao uint32 vbo uint32 ebo uint32 size int32 } func (g Geometry) Draw() { gl.BindVertexArray(g.vao) gl.BindBuffer(gl.ARRAY_BUFFER, g.vbo) gl.DrawElementsWithOffset(gl.TRIANGLES, g.size, gl.UNSIGNED_INT, 0) } func (g Geometry) Delete() { gl.DeleteVertexArrays(1, &g.vao) gl.DeleteBuffers(1, &g.ebo) gl.DeleteBuffers(1, &g.vbo) } type vec struct { Values []float32 } type point struct { Vertex int Normal int Uv int } type face struct { Points [3]point } func new(vertices []vec, normals []vec, uvs []vec, faces []face) (Geometry, error) { fmt.Println(len(vertices), len(normals), len(uvs), len(faces)) i := 0 points := make(map[point]int) indicies := []uint{} for _, face := range faces { for _, point := range face.Points { if val, ok := points[point]; !ok { points[point] = i indicies = append(indicies, uint(i)) i++ } else { indicies = append(indicies, uint(val)) } } } rPoints := make(map[int]point) for k, v := range points { rPoints[v] = k } buffer := make([]float32, len(rPoints)*8) for i := 0; i < len(rPoints); i++ { v := rPoints[i] buffer[i*8+0] = vertices[v.Vertex].Values[0] buffer[i*8+1] = vertices[v.Vertex].Values[1] buffer[i*8+2] = vertices[v.Vertex].Values[2] buffer[i*8+3] = normals[v.Normal].Values[0] buffer[i*8+4] = normals[v.Normal].Values[1] buffer[i*8+5] = normals[v.Normal].Values[2] buffer[i*8+6] = uvs[v.Uv].Values[0] buffer[i*8+7] = uvs[v.Uv].Values[1] } var geometry Geometry // vao gl.GenVertexArrays(1, &geometry.vao) gl.BindVertexArray(geometry.vao) // vbo gl.GenBuffers(1, &geometry.vbo) gl.BindBuffer(gl.ARRAY_BUFFER, geometry.vbo) gl.BufferData(gl.ARRAY_BUFFER, len(buffer)*4, gl.Ptr(buffer), gl.STATIC_DRAW) // attributes gl.VertexAttribPointerWithOffset(0, 3, gl.FLOAT, false, 8*4, 0) gl.EnableVertexAttribArray(0) gl.VertexAttribPointerWithOffset(1, 3, gl.FLOAT, false, 8*4, 3*4) gl.EnableVertexAttribArray(1) gl.VertexAttribPointerWithOffset(2, 2, gl.FLOAT, false, 8*4, 6*4) gl.EnableVertexAttribArray(2) // ebo gl.GenBuffers(1, &geometry.ebo) gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, geometry.ebo) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indicies)*4, gl.Ptr(indicies), gl.STATIC_DRAW) geometry.size = int32(len(indicies)) return geometry, nil } func LoadOBJ(path string) (geometries []Geometry, err error) { file, err := os.Open(path) if err != nil { return nil, err } var vertices []vec var normals []vec var uvs []vec var faces []face scanner := bufio.NewScanner(file) for scanner.Scan() { switch scanner.Text()[0:2] { case "# ": continue case "mt": fmt.Println("material ignored") continue case "o ": if len(vertices) != 0 { geometry, err := new(vertices, normals, uvs, faces) if err != nil { return nil, err } geometries = append(geometries, geometry) } case "v ": parts := strings.Split(scanner.Text(), " ") vertex := vec{} for i := 1; i < 4; i++ { value, err := strconv.ParseFloat(parts[i], 32) if err != nil { return nil, err } vertex.Values = append(vertex.Values, float32(value)) } vertices = append(vertices, vertex) case "vn": parts := strings.Split(scanner.Text(), " ") normal := vec{} for i := 1; i < 4; i++ { value, err := strconv.ParseFloat(parts[i], 32) if err != nil { return nil, err } normal.Values = append(normal.Values, float32(value)) } normals = append(normals, normal) case "vt": parts := strings.Split(scanner.Text(), " ") uv := vec{} for i := 1; i < 3; i++ { value, err := strconv.ParseFloat(parts[i], 32) if err != nil { return nil, err } uv.Values = append(uv.Values, float32(value)) } uvs = append(uvs, uv) case "f ": parts := strings.Split(scanner.Text(), " ") face := face{} for i, part := range parts[1:] { bits := strings.Split(part, "/") v, err := strconv.Atoi(bits[0]) if err != nil { return nil, err } t, err := strconv.Atoi(bits[1]) if err != nil { return nil, err } n, err := strconv.Atoi(bits[2]) if err != nil { return nil, err } face.Points[i].Vertex = v - 1 face.Points[i].Normal = n - 1 face.Points[i].Uv = t - 1 } faces = append(faces, face) } } geometry, err := new(vertices, normals, uvs, faces) if err != nil { return nil, err } geometries = append(geometries, geometry) return geometries, err }