obj.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. // Copyright 2016 The G3N Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package obj
  5. package obj
  6. import (
  7. "bufio"
  8. "errors"
  9. "fmt"
  10. "io"
  11. "math"
  12. "os"
  13. "path/filepath"
  14. "strconv"
  15. "strings"
  16. "github.com/g3n/engine/core"
  17. "github.com/g3n/engine/geometry"
  18. "github.com/g3n/engine/gls"
  19. "github.com/g3n/engine/graphic"
  20. "github.com/g3n/engine/material"
  21. "github.com/g3n/engine/math32"
  22. "github.com/g3n/engine/texture"
  23. )
  24. // Decoder contains all decoded data from the obj and mtl files
  25. type Decoder struct {
  26. Objects []Object // decoded objects
  27. Matlib string // name of the material lib
  28. Materials map[string]*Material // maps material name to object
  29. Vertices math32.ArrayF32 // vertices positions array
  30. Normals math32.ArrayF32 // vertices normals
  31. Uvs math32.ArrayF32 // vertices texture coordinates
  32. Warnings []string // warning messages
  33. line uint // current line number
  34. objCurrent *Object // current object
  35. matCurrent *Material // current material
  36. smoothCurrent bool // current smooth state
  37. mtlDir string // Directory of material file
  38. }
  39. // Object contains all information about one decoded object
  40. type Object struct {
  41. Name string // Object name
  42. Faces []Face // Faces
  43. materials []string // Materials used in this object
  44. }
  45. // Face contains all information about an object face
  46. type Face struct {
  47. Vertices []int // Indices to the face vertices
  48. Uvs []int // Indices to the face UV coordinates
  49. Normals []int // Indices to the face normals
  50. Material string // Material name
  51. Smooth bool // Smooth face
  52. }
  53. // Material contains all information about an object material
  54. type Material struct {
  55. Name string // Material name
  56. Illum int // Illumination model
  57. Opacity float32 // Opacity factor
  58. Refraction float32 // Refraction factor
  59. Shininess float32 // Shininess (specular exponent)
  60. Ambient math32.Color // Ambient color reflectivity
  61. Diffuse math32.Color // Diffuse color reflectivity
  62. Specular math32.Color // Specular color reflectivity
  63. Emissive math32.Color // Emissive color
  64. MapKd string // Texture file linked to diffuse color
  65. }
  66. var defaultMat = &Material{
  67. Diffuse: math32.Color{R: 0.7, G: 0.7, B: 0.7},
  68. Ambient: math32.Color{R: 0.7, G: 0.7, B: 0.7},
  69. Specular: math32.Color{R: 0.5, G: 0.5, B: 0.5},
  70. Shininess: 30.0,
  71. }
  72. // Local constants
  73. const (
  74. blanks = "\r\n\t "
  75. invINDEX = math.MaxUint32
  76. objType = "obj"
  77. mtlType = "mtl"
  78. )
  79. // Decode decodes the specified obj and mtl files returning a decoder
  80. // object and an error.
  81. func Decode(objpath string, mtlpath string) (*Decoder, error) {
  82. // Opens obj file
  83. fobj, err := os.Open(objpath)
  84. if err != nil {
  85. return nil, err
  86. }
  87. defer fobj.Close()
  88. // If path of material file not supplied,
  89. // try to use the base name of the obj file
  90. if len(mtlpath) == 0 {
  91. dir, objfile := filepath.Split(objpath)
  92. ext := filepath.Ext(objfile)
  93. mtlpath = dir + objfile[:len(objfile)-len(ext)] + ".mtl"
  94. }
  95. fmt.Println("USING TEST VERSION")
  96. // Opens mtl file
  97. fmtl, err := os.Open(mtlpath)
  98. defer fmtl.Close() // will produce (ignored) err if fmtl==nil
  99. // fmt.Println("before DecodeReader()")
  100. dec, err := DecodeReader(fobj, fmtl)
  101. if err != nil {
  102. return nil, err
  103. }
  104. // fmt.Println("after DecodeReader()")
  105. dec.mtlDir = filepath.Dir(objpath)
  106. return dec, nil
  107. }
  108. // DecodeReader decodes the specified obj and mtl readers returning a decoder
  109. // object and an error.
  110. func DecodeReader(objreader, mtlreader io.Reader) (*Decoder, error) {
  111. dec := new(Decoder)
  112. dec.Objects = make([]Object, 0)
  113. dec.Warnings = make([]string, 0)
  114. dec.Materials = make(map[string]*Material)
  115. dec.Vertices = math32.NewArrayF32(0, 0)
  116. dec.Normals = math32.NewArrayF32(0, 0)
  117. dec.Uvs = math32.NewArrayF32(0, 0)
  118. dec.line = 1
  119. // Parses obj lines
  120. err := dec.parse(objreader, dec.parseObjLine)
  121. if err != nil {
  122. return nil, err
  123. }
  124. // fmt.Printf("before dec.parse(mtlreader), mtlreader=<%#v>\n", mtlreader)
  125. // Parses mtl lines
  126. // if parsing causes an error, range over the materials named in the OBJ
  127. // file and substitute a default.
  128. dec.matCurrent = nil
  129. dec.line = 1
  130. // fmt.Println("calling dec.parse(mtlreader)")
  131. err = dec.parse(mtlreader, dec.parseMtlLine)
  132. if err != nil {
  133. // handle error by using default material instead
  134. // of simply passing it up the call stack.
  135. // But log it.
  136. for key := range dec.Materials {
  137. dec.Materials[key] = defaultMat
  138. }
  139. fmt.Println("logged warning")
  140. dec.appendWarn(mtlType, "unable to parse a mtl file for obj. using default material instead.")
  141. }
  142. // fmt.Println("after dec.parse(mtlreader)")
  143. return dec, nil
  144. }
  145. // NewGroup creates and returns a group containing as children meshes
  146. // with all the decoded objects.
  147. // A group is returned even if there is only one object decoded.
  148. func (dec *Decoder) NewGroup() (*core.Node, error) {
  149. group := core.NewNode()
  150. for i := 0; i < len(dec.Objects); i++ {
  151. mesh, err := dec.NewMesh(&dec.Objects[i])
  152. if err != nil {
  153. return nil, err
  154. }
  155. group.Add(mesh)
  156. }
  157. return group, nil
  158. }
  159. // NewMesh creates and returns a mesh from an specified decoded object.
  160. func (dec *Decoder) NewMesh(obj *Object) (*graphic.Mesh, error) {
  161. // Creates object geometry
  162. geom, err := dec.NewGeometry(obj)
  163. if err != nil {
  164. return nil, err
  165. }
  166. // defaultMaterial := material.NewPhong(math32.NewColor("gray"))
  167. // Single material
  168. if geom.GroupCount() == 1 {
  169. // fmt.Println("single group geom")
  170. // get Material info from mtl file and ensure it's valid.
  171. // substitute default material if it is not.
  172. var matDesc *Material
  173. var matName string
  174. if len(obj.materials) > 0 {
  175. matName = obj.materials[0]
  176. }
  177. matDesc = dec.Materials[matName]
  178. if matDesc == nil {
  179. matDesc = defaultMat
  180. // log warning
  181. msg := fmt.Sprintf("could not find material for %s. using default material.", obj.Name)
  182. dec.appendWarn(objType, msg)
  183. }
  184. // Creates material for mesh
  185. mat := material.NewPhong(&matDesc.Diffuse)
  186. ambientColor := mat.AmbientColor()
  187. mat.SetAmbientColor(ambientColor.Multiply(&matDesc.Ambient))
  188. mat.SetSpecularColor(&matDesc.Specular)
  189. mat.SetShininess(matDesc.Shininess)
  190. // Loads material textures if specified
  191. err = dec.loadTex(&mat.Material, matDesc)
  192. if err != nil {
  193. return nil, err
  194. }
  195. return graphic.NewMesh(geom, mat), nil
  196. }
  197. // Multi material
  198. // fmt.Println("multi group geom")
  199. mesh := graphic.NewMesh(geom, nil)
  200. for idx := 0; idx < geom.GroupCount(); idx++ {
  201. group := geom.GroupAt(idx)
  202. // get Material info from mtl file and ensure it's valid.
  203. // substitute default material if it is not.
  204. var matDesc *Material
  205. var matName string
  206. if len(obj.materials) > group.Matindex {
  207. matName = obj.materials[group.Matindex]
  208. }
  209. matDesc = dec.Materials[matName]
  210. if matDesc == nil {
  211. matDesc = defaultMat
  212. // log warning
  213. msg := fmt.Sprintf("could not find material for %s. using default material.", obj.Name)
  214. dec.appendWarn(objType, msg)
  215. }
  216. // Creates material for mesh
  217. matGroup := material.NewPhong(&matDesc.Diffuse)
  218. ambientColor := matGroup.AmbientColor()
  219. matGroup.SetAmbientColor(ambientColor.Multiply(&matDesc.Ambient))
  220. matGroup.SetSpecularColor(&matDesc.Specular)
  221. matGroup.SetShininess(matDesc.Shininess)
  222. // Loads material textures if specified
  223. err = dec.loadTex(&matGroup.Material, matDesc)
  224. if err != nil {
  225. return nil, err
  226. }
  227. mesh.AddGroupMaterial(matGroup, idx)
  228. }
  229. return mesh, nil
  230. }
  231. // NewGeometry generates and returns a geometry from the specified object
  232. func (dec *Decoder) NewGeometry(obj *Object) (*geometry.Geometry, error) {
  233. geom := geometry.NewGeometry()
  234. // Create buffers
  235. positions := math32.NewArrayF32(0, 0)
  236. normals := math32.NewArrayF32(0, 0)
  237. uvs := math32.NewArrayF32(0, 0)
  238. indices := math32.NewArrayU32(0, 0)
  239. // copy all vertex info from the decoded Object, face and index to the geometry
  240. copyVertex := func(face *Face, idx int) {
  241. var vec3 math32.Vector3
  242. var vec2 math32.Vector2
  243. pos := positions.Size() / 3
  244. // Copy vertex position and append to geometry
  245. dec.Vertices.GetVector3(3*face.Vertices[idx], &vec3)
  246. positions.AppendVector3(&vec3)
  247. // Copy vertex normal and append to geometry
  248. if face.Normals[idx] != invINDEX {
  249. dec.Normals.GetVector3(3*face.Normals[idx], &vec3)
  250. normals.AppendVector3(&vec3)
  251. }
  252. // Copy vertex uv and append to geometry
  253. if face.Uvs[idx] != invINDEX {
  254. dec.Uvs.GetVector2(2*face.Uvs[idx], &vec2)
  255. uvs.AppendVector2(&vec2)
  256. }
  257. indices.Append(uint32(pos))
  258. }
  259. var group *geometry.Group
  260. matName := ""
  261. matIndex := 0
  262. for _, face := range obj.Faces {
  263. // If face material changed, starts a new group
  264. if face.Material != matName {
  265. group = geom.AddGroup(indices.Size(), 0, matIndex)
  266. matName = face.Material
  267. matIndex++
  268. }
  269. // Copy face vertices to geometry
  270. for idx := 1; idx < len(face.Vertices)-1; idx++ {
  271. copyVertex(&face, 0)
  272. copyVertex(&face, idx)
  273. copyVertex(&face, idx+1)
  274. group.Count += 3
  275. }
  276. }
  277. geom.SetIndices(indices)
  278. geom.AddVBO(gls.NewVBO(positions).AddAttrib(gls.VertexPosition))
  279. geom.AddVBO(gls.NewVBO(normals).AddAttrib(gls.VertexNormal))
  280. geom.AddVBO(gls.NewVBO(uvs).AddAttrib(gls.VertexTexcoord))
  281. return geom, nil
  282. }
  283. // loadTex loads textures described in the material descriptor into the
  284. // specified material
  285. func (dec *Decoder) loadTex(mat *material.Material, desc *Material) error {
  286. // Checks if material descriptor specified texture
  287. if desc.MapKd == "" {
  288. return nil
  289. }
  290. // Get texture file path
  291. // If texture file path is not absolute assumes it is relative
  292. // to the directory of the material file
  293. var texPath string
  294. if filepath.IsAbs(desc.MapKd) {
  295. texPath = desc.MapKd
  296. } else {
  297. texPath = filepath.Join(dec.mtlDir, desc.MapKd)
  298. }
  299. // Try to load texture from image file
  300. tex, err := texture.NewTexture2DFromImage(texPath)
  301. if err != nil {
  302. return err
  303. }
  304. mat.AddTexture(tex)
  305. return nil
  306. }
  307. // parse reads the lines from the specified reader and dispatch them
  308. // to the specified line parser.
  309. func (dec *Decoder) parse(reader io.Reader, parseLine func(string) error) error {
  310. bufin := bufio.NewReader(reader)
  311. dec.line = 1
  312. for {
  313. // Reads next line and abort on errors (not EOF)
  314. line, err := bufin.ReadString('\n')
  315. if err != nil && err != io.EOF {
  316. return err
  317. }
  318. // Parses the line
  319. line = strings.Trim(line, blanks)
  320. perr := parseLine(line)
  321. if perr != nil {
  322. return perr
  323. }
  324. // If EOF ends of parsing.
  325. if err == io.EOF {
  326. break
  327. }
  328. dec.line++
  329. }
  330. return nil
  331. }
  332. // Parses obj file line, dispatching to specific parsers
  333. func (dec *Decoder) parseObjLine(line string) error {
  334. // Ignore empty lines
  335. fields := strings.Fields(line)
  336. if len(fields) == 0 {
  337. return nil
  338. }
  339. // Ignore comment lines
  340. ltype := fields[0]
  341. if strings.HasPrefix(ltype, "#") {
  342. return nil
  343. }
  344. switch ltype {
  345. // Material library
  346. case "mtllib":
  347. return dec.parseMatlib(fields[1:])
  348. // Object name
  349. case "o":
  350. return dec.parseObject(fields[1:])
  351. // Group names. We are considering "group" the same as "object"
  352. // This may not be right
  353. case "g":
  354. return dec.parseObject(fields[1:])
  355. // Vertex coordinate
  356. case "v":
  357. return dec.parseVertex(fields[1:])
  358. // Vertex normal coordinate
  359. case "vn":
  360. return dec.parseNormal(fields[1:])
  361. // Vertex texture coordinate
  362. case "vt":
  363. return dec.parseTex(fields[1:])
  364. // Face vertex
  365. case "f":
  366. return dec.parseFace(fields[1:])
  367. // Use material
  368. case "usemtl":
  369. return dec.parseUsemtl(fields[1:])
  370. // Smooth
  371. case "s":
  372. return dec.parseSmooth(fields[1:])
  373. default:
  374. dec.appendWarn(objType, "field not supported: "+ltype)
  375. }
  376. return nil
  377. }
  378. // Parses a mtllib line:
  379. // mtllib <name>
  380. func (dec *Decoder) parseMatlib(fields []string) error {
  381. if len(fields) < 1 {
  382. return errors.New("Object line (o) with less than 2 fields")
  383. }
  384. dec.Matlib = fields[0]
  385. return nil
  386. }
  387. // Parses an object line:
  388. // o <name>
  389. func (dec *Decoder) parseObject(fields []string) error {
  390. if len(fields) < 1 {
  391. return errors.New("Object line (o) with less than 2 fields")
  392. }
  393. dec.Objects = append(dec.Objects, makeObject(fields[0]))
  394. dec.objCurrent = &dec.Objects[len(dec.Objects)-1]
  395. return nil
  396. }
  397. // makes an Object with name.
  398. func makeObject(name string) Object {
  399. var ob Object
  400. ob.Name = name
  401. ob.Faces = make([]Face, 0)
  402. ob.materials = make([]string, 0)
  403. return ob
  404. }
  405. // Parses a vertex position line
  406. // v <x> <y> <z> [w]
  407. func (dec *Decoder) parseVertex(fields []string) error {
  408. if len(fields) < 3 {
  409. return errors.New("Less than 3 vertices in 'v' line")
  410. }
  411. for _, f := range fields[:3] {
  412. val, err := strconv.ParseFloat(f, 32)
  413. if err != nil {
  414. return err
  415. }
  416. dec.Vertices.Append(float32(val))
  417. }
  418. return nil
  419. }
  420. // Parses a vertex normal line
  421. // vn <x> <y> <z>
  422. func (dec *Decoder) parseNormal(fields []string) error {
  423. if len(fields) < 3 {
  424. return errors.New("Less than 3 normals in 'vn' line")
  425. }
  426. for _, f := range fields[:3] {
  427. val, err := strconv.ParseFloat(f, 32)
  428. if err != nil {
  429. return err
  430. }
  431. dec.Normals.Append(float32(val))
  432. }
  433. return nil
  434. }
  435. // Parses a vertex texture coordinate line:
  436. // vt <u> <v> <w>
  437. func (dec *Decoder) parseTex(fields []string) error {
  438. if len(fields) < 2 {
  439. return errors.New("Less than 2 texture coords. in 'vt' line")
  440. }
  441. for _, f := range fields[:2] {
  442. val, err := strconv.ParseFloat(f, 32)
  443. if err != nil {
  444. return err
  445. }
  446. dec.Uvs.Append(float32(val))
  447. }
  448. return nil
  449. }
  450. // parseFace parses a face decription line:
  451. // f v1[/vt1][/vn1] v2[/vt2][/vn2] v3[/vt3][/vn3] ...
  452. func (dec *Decoder) parseFace(fields []string) error {
  453. // NOTE(quillaja): this wasn't really part of the original issue-29
  454. if dec.objCurrent == nil {
  455. // if a face line is encountered before a group (g) or object (o),
  456. // create a new "default" object. This 'handles' the case when
  457. // a g or o line is not specified (allowed in OBJ format)
  458. dec.parseObject([]string{fmt.Sprintf("unnamed%d", dec.line)})
  459. }
  460. // If current object has no material, appends last material if defined
  461. if len(dec.objCurrent.materials) == 0 && dec.matCurrent != nil {
  462. dec.objCurrent.materials = append(dec.objCurrent.materials, dec.matCurrent.Name)
  463. }
  464. if len(fields) < 3 {
  465. return dec.formatError("Face line with less 3 fields")
  466. }
  467. var face Face
  468. face.Vertices = make([]int, len(fields))
  469. face.Uvs = make([]int, len(fields))
  470. face.Normals = make([]int, len(fields))
  471. if dec.matCurrent != nil {
  472. face.Material = dec.matCurrent.Name
  473. } else {
  474. // TODO (Ben): do something better than spamming warnings for each line
  475. // dec.appendWarn(objType, "No material defined")
  476. face.Material = "internal default" // causes error on in NewGeom() if ""
  477. // dec.matCurrent = defaultMat
  478. }
  479. face.Smooth = dec.smoothCurrent
  480. for pos, f := range fields {
  481. // Separate the current field in its components: v vt vn
  482. vfields := strings.Split(f, "/")
  483. if len(vfields) < 1 {
  484. return dec.formatError("Face field with no parts")
  485. }
  486. // Get the index of this vertex position (must always exist)
  487. val, err := strconv.ParseInt(vfields[0], 10, 32)
  488. if err != nil {
  489. return err
  490. }
  491. // Positive index is an absolute vertex index
  492. if val > 0 {
  493. face.Vertices[pos] = int(val - 1)
  494. // Negative vertex index is relative to the last parsed vertex
  495. } else if val < 0 {
  496. current := (len(dec.Vertices) / 3) - 1
  497. face.Vertices[pos] = current + int(val) + 1
  498. // Vertex index could never be 0
  499. } else {
  500. return dec.formatError("Face vertex index value equal to 0")
  501. }
  502. // Get the index of this vertex UV coordinate (optional)
  503. if len(vfields) > 1 && len(vfields[1]) > 0 {
  504. val, err := strconv.ParseInt(vfields[1], 10, 32)
  505. if err != nil {
  506. return err
  507. }
  508. // Positive index is an absolute UV index
  509. if val > 0 {
  510. face.Uvs[pos] = int(val - 1)
  511. // Negative vertex index is relative to the last parsed uv
  512. } else if val < 0 {
  513. current := (len(dec.Uvs) / 2) - 1
  514. face.Uvs[pos] = current + int(val) + 1
  515. // UV index could never be 0
  516. } else {
  517. return dec.formatError("Face uv index value equal to 0")
  518. }
  519. } else {
  520. face.Uvs[pos] = invINDEX
  521. }
  522. // Get the index of this vertex normal (optional)
  523. if len(vfields) >= 3 {
  524. val, err = strconv.ParseInt(vfields[2], 10, 32)
  525. if err != nil {
  526. return err
  527. }
  528. // Positive index is an absolute normal index
  529. if val > 0 {
  530. face.Normals[pos] = int(val - 1)
  531. // Negative vertex index is relative to the last parsed normal
  532. } else if val < 0 {
  533. current := (len(dec.Normals) / 3) - 1
  534. face.Normals[pos] = current + int(val) + 1
  535. // Normal index could never be 0
  536. } else {
  537. return dec.formatError("Face normal index value equal to 0")
  538. }
  539. } else {
  540. face.Normals[pos] = invINDEX
  541. }
  542. }
  543. // Appends this face to the current object
  544. dec.objCurrent.Faces = append(dec.objCurrent.Faces, face)
  545. return nil
  546. }
  547. // parseUsemtl parses a "usemtl" decription line:
  548. // usemtl <name>
  549. func (dec *Decoder) parseUsemtl(fields []string) error {
  550. if len(fields) < 1 {
  551. return dec.formatError("Usemtl with no fields")
  552. }
  553. // NOTE(quillaja): see similar nil test in parseFace()
  554. if dec.objCurrent == nil {
  555. dec.parseObject([]string{fmt.Sprintf("unnamed%d", dec.line)})
  556. }
  557. // Checks if this material has already been parsed
  558. name := fields[0]
  559. mat := dec.Materials[name]
  560. // Creates material descriptor
  561. if mat == nil {
  562. mat = new(Material)
  563. mat.Name = name
  564. dec.Materials[name] = mat
  565. }
  566. dec.objCurrent.materials = append(dec.objCurrent.materials, name)
  567. // Set this as the current material
  568. dec.matCurrent = mat
  569. return nil
  570. }
  571. // parseSmooth parses a "s" decription line:
  572. // s <0|1>
  573. func (dec *Decoder) parseSmooth(fields []string) error {
  574. if len(fields) < 1 {
  575. return dec.formatError("'s' with no fields")
  576. }
  577. if fields[0] == "0" || fields[0] == "off" {
  578. dec.smoothCurrent = false
  579. return nil
  580. }
  581. if fields[0] == "1" || fields[0] == "on" {
  582. dec.smoothCurrent = true
  583. return nil
  584. }
  585. return dec.formatError("'s' with invalid value")
  586. }
  587. /******************************************************************************
  588. mtl parse functions
  589. */
  590. // Parses material file line, dispatching to specific parsers
  591. func (dec *Decoder) parseMtlLine(line string) error {
  592. // Ignore empty lines
  593. fields := strings.Fields(line)
  594. if len(fields) == 0 {
  595. return nil
  596. }
  597. // Ignore comment lines
  598. ltype := fields[0]
  599. if strings.HasPrefix(ltype, "#") {
  600. return nil
  601. }
  602. switch ltype {
  603. case "newmtl":
  604. return dec.parseNewmtl(fields[1:])
  605. case "d":
  606. return dec.parseDissolve(fields[1:])
  607. case "Ka":
  608. return dec.parseKa(fields[1:])
  609. case "Kd":
  610. return dec.parseKd(fields[1:])
  611. case "Ke":
  612. return dec.parseKe(fields[1:])
  613. case "Ks":
  614. return dec.parseKs(fields[1:])
  615. case "Ni":
  616. return dec.parseNi(fields[1:])
  617. case "Ns":
  618. return dec.parseNs(fields[1:])
  619. case "illum":
  620. return dec.parseIllum(fields[1:])
  621. case "map_Kd":
  622. return dec.parseMapKd(fields[1:])
  623. default:
  624. dec.appendWarn(mtlType, "field not supported: "+ltype)
  625. }
  626. return nil
  627. }
  628. // Parses new material definition
  629. // newmtl <mat_name>
  630. func (dec *Decoder) parseNewmtl(fields []string) error {
  631. if len(fields) < 1 {
  632. return dec.formatError("newmtl with no fields")
  633. }
  634. // Checks if material has already been seen
  635. name := fields[0]
  636. mat := dec.Materials[name]
  637. // Creates material descriptor
  638. if mat == nil {
  639. mat = new(Material)
  640. mat.Name = name
  641. dec.Materials[name] = mat
  642. }
  643. dec.matCurrent = mat
  644. return nil
  645. }
  646. // Parses the dissolve factor (opacity)
  647. // d <factor>
  648. func (dec *Decoder) parseDissolve(fields []string) error {
  649. if len(fields) < 1 {
  650. return dec.formatError("'d' with no fields")
  651. }
  652. val, err := strconv.ParseFloat(fields[0], 32)
  653. if err != nil {
  654. return dec.formatError("'d' parse float error")
  655. }
  656. dec.matCurrent.Opacity = float32(val)
  657. return nil
  658. }
  659. // Parses ambient reflectivity:
  660. // Ka r g b
  661. func (dec *Decoder) parseKa(fields []string) error {
  662. if len(fields) < 3 {
  663. return dec.formatError("'Ka' with less than 3 fields")
  664. }
  665. var colors [3]float32
  666. for pos, f := range fields[:3] {
  667. val, err := strconv.ParseFloat(f, 32)
  668. if err != nil {
  669. return err
  670. }
  671. colors[pos] = float32(val)
  672. }
  673. dec.matCurrent.Ambient.Set(colors[0], colors[1], colors[2])
  674. return nil
  675. }
  676. // Parses diffuse reflectivity:
  677. // Kd r g b
  678. func (dec *Decoder) parseKd(fields []string) error {
  679. if len(fields) < 3 {
  680. return dec.formatError("'Kd' with less than 3 fields")
  681. }
  682. var colors [3]float32
  683. for pos, f := range fields[:3] {
  684. val, err := strconv.ParseFloat(f, 32)
  685. if err != nil {
  686. return err
  687. }
  688. colors[pos] = float32(val)
  689. }
  690. dec.matCurrent.Diffuse.Set(colors[0], colors[1], colors[2])
  691. return nil
  692. }
  693. // Parses emissive color:
  694. // Ke r g b
  695. func (dec *Decoder) parseKe(fields []string) error {
  696. if len(fields) < 3 {
  697. return dec.formatError("'Ke' with less than 3 fields")
  698. }
  699. var colors [3]float32
  700. for pos, f := range fields[:3] {
  701. val, err := strconv.ParseFloat(f, 32)
  702. if err != nil {
  703. return err
  704. }
  705. colors[pos] = float32(val)
  706. }
  707. dec.matCurrent.Emissive.Set(colors[0], colors[1], colors[2])
  708. return nil
  709. }
  710. // Parses specular reflectivity:
  711. // Ks r g b
  712. func (dec *Decoder) parseKs(fields []string) error {
  713. if len(fields) < 3 {
  714. return dec.formatError("'Ks' with less than 3 fields")
  715. }
  716. var colors [3]float32
  717. for pos, f := range fields[:3] {
  718. val, err := strconv.ParseFloat(f, 32)
  719. if err != nil {
  720. return err
  721. }
  722. colors[pos] = float32(val)
  723. }
  724. dec.matCurrent.Specular.Set(colors[0], colors[1], colors[2])
  725. return nil
  726. }
  727. // Parses optical density, also known as index of refraction
  728. // Ni <optical_density>
  729. func (dec *Decoder) parseNi(fields []string) error {
  730. if len(fields) < 1 {
  731. return dec.formatError("'Ni' with no fields")
  732. }
  733. val, err := strconv.ParseFloat(fields[0], 32)
  734. if err != nil {
  735. return dec.formatError("'d' parse float error")
  736. }
  737. dec.matCurrent.Refraction = float32(val)
  738. return nil
  739. }
  740. // Parses specular exponent
  741. // Ns <specular_exponent>
  742. func (dec *Decoder) parseNs(fields []string) error {
  743. if len(fields) < 1 {
  744. return dec.formatError("'Ns' with no fields")
  745. }
  746. val, err := strconv.ParseFloat(fields[0], 32)
  747. if err != nil {
  748. return dec.formatError("'d' parse float error")
  749. }
  750. dec.matCurrent.Shininess = float32(val)
  751. return nil
  752. }
  753. // Parses illumination model (0 to 10)
  754. // illum <ilum_#>
  755. func (dec *Decoder) parseIllum(fields []string) error {
  756. if len(fields) < 1 {
  757. return dec.formatError("'illum' with no fields")
  758. }
  759. val, err := strconv.ParseUint(fields[0], 10, 32)
  760. if err != nil {
  761. return dec.formatError("'d' parse int error")
  762. }
  763. dec.matCurrent.Illum = int(val)
  764. return nil
  765. }
  766. // Parses color texture linked to the diffuse reflectivity of the material
  767. // map_Kd [-options] <filename>
  768. func (dec *Decoder) parseMapKd(fields []string) error {
  769. if len(fields) < 1 {
  770. return dec.formatError("No fields")
  771. }
  772. dec.matCurrent.MapKd = fields[0]
  773. return nil
  774. }
  775. func (dec *Decoder) formatError(msg string) error {
  776. return fmt.Errorf("%s in line:%d", msg, dec.line)
  777. }
  778. func (dec *Decoder) appendWarn(ftype string, msg string) {
  779. wline := fmt.Sprintf("%s(%d): %s", ftype, dec.line, msg)
  780. dec.Warnings = append(dec.Warnings, wline)
  781. }