commit a2419b804ccf86a284bda8279f5be739d549db78
parent 7ee1a21d4944ed1d8810757b52d8bc3b1611859e
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sat, 16 Nov 2024 17:52:01 +0900
load obj file
Diffstat:
| M | cmd/sample/main.go |  |  | 17 | ++++++++++++++++- | 
| M | object.go |  |  | 94 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- | 
2 files changed, 108 insertions(+), 3 deletions(-)
diff --git a/cmd/sample/main.go b/cmd/sample/main.go
@@ -3,6 +3,7 @@ package main
 import (
 	"log"
 	"math"
+	"os"
 	"path/filepath"
 	"runtime"
 	"time"
@@ -75,7 +76,9 @@ func watchCursor(app *App) {
 	}
 }
 
-var object = tofu.Object{
+var teapot *tofu.Object
+
+var object = &tofu.Object{
 	Vertices: []tofu.Vec3{
 		tofu.Vec3{0.5, 0.5, -0.5},
 		tofu.Vec3{0.5, -0.5, -0.5},
@@ -192,6 +195,7 @@ func (app *App) Update() error {
 		app.program.SetMat4("model", model)
 		object.Draw()
 	}
+	teapot.Draw()
 
 	app.lightProgram.Use()
 	app.program.SetMat4("view", view)
@@ -228,6 +232,17 @@ func main() {
 	lightFpath := filepath.Join(filepath.Dir(f), "light_fragment.glsl")
 	texturePath := filepath.Join(filepath.Dir(f), "container2.png")
 	specularMapPath := filepath.Join(filepath.Dir(f), "container2_specular.png")
+	teapotPath := filepath.Join(filepath.Dir(f), "teapot.obj")
+
+	tf, err := os.Open(teapotPath)
+	if err != nil {
+		log.Fatal(err)
+	}
+	teapot, err = tofu.DecodeObject(tf)
+	if err != nil {
+		log.Fatal(err)
+	}
+	teapot.Load()
 
 	app.program, err = tofu.NewProgram(vpath, fpath)
 	if err != nil {
diff --git a/object.go b/object.go
@@ -1,21 +1,109 @@
 package tofu
 
 import (
-	"image/color"
+	"fmt"
+	"io"
+	"log"
 	"math"
+	"strconv"
+	"text/scanner"
 
 	"github.com/go-gl/gl/v3.3-core/gl"
 )
 
 type Object struct {
 	Vertices  []Vec3
-	Colors    []color.Color
 	TexCoords []Vec2
 	Normals   []Vec3
 	Faces     []Face
 	vao       *VAO
 }
 
+func DecodeObject(r io.Reader) (*Object, error) {
+	obj := new(Object)
+	s := new(scanner.Scanner)
+	s.Init(r)
+	for {
+		t := s.Scan()
+		if t == scanner.EOF {
+			break
+		}
+		if t != scanner.Ident {
+			log.Println(t)
+			return nil, fmt.Errorf("unwanted token: %s, want Ident", s.TokenText())
+		}
+		switch ident := s.TokenText(); ident {
+		case "v":
+			if err := obj.addVertex(s); err != nil {
+				return nil, err
+			}
+		case "f":
+			if err := obj.addFace(s); err != nil {
+				return nil, err
+			}
+		default:
+			log.Println("ident %s not implemented. ignoring.", ident)
+		}
+	}
+	return obj, nil
+}
+
+func (obj *Object) addVertex(s *scanner.Scanner) error {
+	var v Vec3
+	for i := 0; i < 3; i++ {
+		t := s.Scan()
+		switch t {
+		case scanner.Float, scanner.Int, '-':
+			sign := float32(1)
+			if t == '-' {
+				sign = -1
+				t = s.Scan()
+				if t != scanner.Float && t != scanner.Int {
+					return fmt.Errorf("unwanted token %q of type %d. want vertex coordinate.", s.TokenText(), t)
+				}
+			}
+			x, err := strconv.ParseFloat(s.TokenText(), 64)
+			if err != nil {
+				return fmt.Errorf("parseFloat: %v", err)
+			}
+			v[i] = float32(x) * sign
+		default:
+			return fmt.Errorf("unwanted token %q of type %d. want vertex coordinate.", s.TokenText(), t)
+		}
+	}
+	obj.Vertices = append(obj.Vertices, v)
+	return nil
+}
+
+func (obj *Object) addFace(s *scanner.Scanner) error {
+	var f Face
+	for i := 0; i < 3; i++ {
+		t := s.Scan()
+		switch t {
+		case scanner.Int, '-':
+			sign := int(1)
+			if t == '-' {
+				sign = -1
+				t = s.Scan()
+				if t != scanner.Int {
+					return fmt.Errorf("unwanted token %q of type %d. face index", s.TokenText(), t)
+				}
+			}
+			x, err := strconv.Atoi(s.TokenText())
+			if err != nil {
+				return fmt.Errorf("Atoi: %v", err)
+			}
+			f.I[i].V = x*sign - 1
+			f.I[i].N = NoIndex
+			f.I[i].T = NoIndex
+		default:
+			return fmt.Errorf("unwanted token %q of type %d. want face index.", s.TokenText(), t)
+		}
+	}
+	obj.Faces = append(obj.Faces, f)
+	return nil
+}
+
 var NoIndex = math.MinInt
 
 type VertexIndex struct {
@@ -85,6 +173,8 @@ func (obj *Object) Load() {
 }
 
 func (obj *Object) Draw() {
+	// TODO: performance?
+	obj.vao.bind()
 	gl.DrawElements(gl.TRIANGLES,
 		int32(obj.stride()*3*len(obj.Faces)),
 		gl.UNSIGNED_INT, nil)