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)