zworld-demo/plugin/objloader/parser.go
2023-12-22 22:04:27 +08:00

112 lines
2.2 KiB
Go

package objloader
import (
"os"
"zworld/library/zos"
"zworld/plugin/math/vec3"
)
type FByteView = zos.FByteView
type FVertex struct {
pos int32
nor int32
tex int32
}
type FMesh struct {
Positions []vec3.T
Normals []vec3.T
TexCoords []vec3.T
Faces [][]FVertex
Indices []uint16
}
type FObjLoader struct {
reader *zos.FReader
mesh *FMesh
}
func (l *FObjLoader) GetTexCoord(bv *FByteView) error {
x := bv.GetFloat()
y := bv.GetFloat()
if err := bv.Err(); err != nil {
return err
}
w := bv.GetFloat()
if bv.Err() != nil {
w = 0
}
v := vec3.T{X: x, Y: y, Z: w}
l.mesh.TexCoords = append(l.mesh.TexCoords, v)
return nil
}
func (l *FObjLoader) GetPosition(bv *FByteView) error {
x := bv.GetFloat()
y := bv.GetFloat()
z := bv.GetFloat()
if err := bv.Err(); err != nil {
return err
}
v := vec3.T{X: x, Y: y, Z: z}
l.mesh.Positions = append(l.mesh.Positions, v)
return nil
}
func (l *FObjLoader) GetNormal(bv *FByteView) error {
x := bv.GetFloat()
y := bv.GetFloat()
z := bv.GetFloat()
if err := bv.Err(); err != nil {
return err
}
v := vec3.T{X: x, Y: y, Z: z}
l.mesh.Normals = append(l.mesh.Normals, v)
return nil
}
func (l *FObjLoader) GetFace(b *FByteView) error {
var faces []FVertex
for i := 0; i < 3; i++ {
line := b.GetToken()
bv := zos.NewByteView(line)
bv.SetSign('/')
v := FVertex{}
v.pos = bv.GetInt()
if err := bv.Err(); err != nil {
return err
}
v.nor = bv.GetInt()
v.tex = bv.GetInt()
faces = append(faces, v)
}
l.mesh.Faces = append(l.mesh.Faces, faces)
return nil
}
func (l *FObjLoader) Parse() error {
for line, err := l.reader.ReadLine(); err == nil; line, err = l.reader.ReadLine() {
bv := zos.NewByteView(line)
bv.SkipWhitespace()
token := string(bv.ReadTokenBySpace())
//zlog.Infof("line {}", string(line))
switch token {
case "v":
err = l.GetPosition(bv)
case "vt":
err = l.GetTexCoord(bv)
case "vn":
err = l.GetNormal(bv)
case "f":
err = l.GetFace(bv)
}
if err != nil {
return err
}
}
return nil
}
func LoadObj(filename string) (err error, mesh *FMesh) {
file, err := os.Open(filename)
if err != nil {
return err, nil
}
l := &FObjLoader{reader: zos.NewReader(file), mesh: &FMesh{}}
err = l.Parse()
return err, l.mesh
}