collada.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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 collada
  5. import (
  6. "encoding/xml"
  7. "fmt"
  8. "github.com/g3n/engine/geometry"
  9. "github.com/g3n/engine/material"
  10. "github.com/g3n/engine/texture"
  11. "io"
  12. "os"
  13. )
  14. // Decoder contains all decoded data from collada file
  15. type Decoder struct {
  16. xmldec *xml.Decoder // xml decoder used internally
  17. lastToken interface{} // last token read
  18. dom Collada // Collada dom
  19. dirImages string // Base directory for images
  20. geometries map[string]geomInstance // Instanced geometries by id
  21. materials map[string]material.IMaterial // Instanced materials by id
  22. tex2D map[string]*texture.Texture2D // Instanced textures 2D by id
  23. }
  24. type geomInstance struct {
  25. geom geometry.IGeometry
  26. ptype uint32
  27. }
  28. // Decode decodes the specified collada file returning a decoder object and an error.
  29. func Decode(filepath string) (*Decoder, error) {
  30. // Opens file
  31. f, err := os.Open(filepath)
  32. if err != nil {
  33. return nil, err
  34. }
  35. defer f.Close()
  36. return DecodeReader(f)
  37. }
  38. // DecodeReader decodes the specified collada reader returning a decoder object and an error.
  39. func DecodeReader(f io.Reader) (*Decoder, error) {
  40. d := new(Decoder)
  41. d.xmldec = xml.NewDecoder(f)
  42. d.geometries = make(map[string]geomInstance)
  43. d.materials = make(map[string]material.IMaterial)
  44. d.tex2D = make(map[string]*texture.Texture2D)
  45. err := d.decCollada(&d.dom)
  46. if err != nil {
  47. return nil, err
  48. }
  49. return d, nil
  50. }
  51. func (d *Decoder) SetDirImages(path string) {
  52. d.dirImages = path
  53. }
  54. //
  55. // Collada DOM root
  56. //
  57. type Collada struct {
  58. Version string
  59. Asset Asset
  60. LibraryAnimations *LibraryAnimations
  61. LibraryImages *LibraryImages
  62. LibraryLights *LibraryLights
  63. LibraryEffects *LibraryEffects
  64. LibraryMaterials *LibraryMaterials
  65. LibraryGeometries *LibraryGeometries
  66. LibraryVisualScenes *LibraryVisualScenes
  67. Scene *Scene
  68. }
  69. //
  70. // Dump writes to the specified writer a text dump of the decoded Collada DOM
  71. // to aid debugging.
  72. //
  73. func (d *Decoder) Dump(out io.Writer, indent int) {
  74. fmt.Fprintf(out, "%sCollada version:%s\n", sIndent(indent), d.dom.Version)
  75. d.dom.Asset.Dump(out, indent+step)
  76. d.dom.LibraryAnimations.Dump(out, indent+step)
  77. d.dom.LibraryImages.Dump(out, indent+step)
  78. d.dom.LibraryLights.Dump(out, indent+step)
  79. d.dom.LibraryEffects.Dump(out, indent+step)
  80. d.dom.LibraryMaterials.Dump(out, indent+step)
  81. d.dom.LibraryGeometries.Dump(out, indent+step)
  82. d.dom.LibraryVisualScenes.Dump(out, indent+step)
  83. d.dom.Scene.Dump(out, indent+step)
  84. }
  85. //
  86. // Contributor
  87. //
  88. type Contributor struct {
  89. Author string
  90. AuthorEmail string
  91. AuthorWebsite string
  92. AuthoringTool string
  93. Comments string
  94. Copyright string
  95. SourceData string
  96. }
  97. // Dump prints out information about the Contributor
  98. func (c *Contributor) Dump(out io.Writer, indent int) {
  99. fmt.Fprintf(out, "%sContributor:\n", sIndent(indent))
  100. ind := indent + step
  101. if len(c.Author) > 0 {
  102. fmt.Fprintf(out, "%sAuthor:%s\n", sIndent(ind), c.Author)
  103. }
  104. if len(c.AuthorEmail) > 0 {
  105. fmt.Fprintf(out, "%sAuthorEmail:%s\n", sIndent(ind), c.AuthorEmail)
  106. }
  107. if len(c.AuthorWebsite) > 0 {
  108. fmt.Fprintf(out, "%sAuthorWebsite:%s\n", sIndent(ind), c.AuthorWebsite)
  109. }
  110. if len(c.AuthoringTool) > 0 {
  111. fmt.Fprintf(out, "%sAuthoringTool:%s\n", sIndent(ind), c.AuthoringTool)
  112. }
  113. if len(c.Comments) > 0 {
  114. fmt.Fprintf(out, "%sComments:%s\n", sIndent(ind), c.Comments)
  115. }
  116. if len(c.Copyright) > 0 {
  117. fmt.Fprintf(out, "%sCopyright:%s\n", sIndent(ind), c.Copyright)
  118. }
  119. if len(c.SourceData) > 0 {
  120. fmt.Fprintf(out, "%sSourceData:%s\n", sIndent(ind), c.SourceData)
  121. }
  122. }
  123. //
  124. // Asset
  125. //
  126. type Asset struct {
  127. Contributor Contributor
  128. Created string
  129. Modified string
  130. UpAxis string
  131. }
  132. // Dump prints out information about the Asset
  133. func (a *Asset) Dump(out io.Writer, indent int) {
  134. fmt.Fprintf(out, "%sAsset:\n", sIndent(indent))
  135. ind := indent + step
  136. a.Contributor.Dump(out, ind)
  137. fmt.Fprintf(out, "%sCreated:%s\n", sIndent(ind), a.Created)
  138. fmt.Fprintf(out, "%sModified:%s\n", sIndent(ind), a.Modified)
  139. fmt.Fprintf(out, "%sUpAxis:%s\n", sIndent(ind), a.UpAxis)
  140. }
  141. //
  142. // Scene
  143. //
  144. type Scene struct {
  145. InstanceVisualScene *InstanceVisualScene
  146. }
  147. // Dump prints out information about the Scene
  148. func (s *Scene) Dump(out io.Writer, indent int) {
  149. fmt.Fprintf(out, "%sScene:\n", sIndent(indent))
  150. ind := indent + step
  151. s.InstanceVisualScene.Dump(out, ind)
  152. }
  153. //
  154. // InstanceVisualScene
  155. //
  156. type InstanceVisualScene struct {
  157. Sid string
  158. Name string
  159. Url string
  160. }
  161. // Dump prints out information about the InstanceVisualScene
  162. func (ivs *InstanceVisualScene) Dump(out io.Writer, indent int) {
  163. if ivs == nil {
  164. return
  165. }
  166. fmt.Fprintf(out, "%sInstanceVisualScene sid:%s name:%s url:%s\n",
  167. sIndent(indent), ivs.Sid, ivs.Name, ivs.Url)
  168. }
  169. func (d *Decoder) decCollada(dom *Collada) error {
  170. // Loop to read all first level elements
  171. var tok interface{}
  172. var err error
  173. first := true
  174. for {
  175. // Reads next token
  176. tok, err = d.xmldec.Token()
  177. if err == io.EOF {
  178. return nil
  179. }
  180. // If not a start element ignore and continue
  181. start, ok := tok.(xml.StartElement)
  182. if !ok {
  183. continue
  184. }
  185. // First element must be "COLLADA"
  186. if first {
  187. if start.Name.Local != "COLLADA" {
  188. return fmt.Errorf("Not a COLLADA file")
  189. }
  190. first = false
  191. dom.Version = findAttrib(start, "version").Value
  192. continue
  193. }
  194. // Decode specified start elements
  195. if start.Name.Local == "asset" {
  196. err = d.decAsset(start, &dom.Asset)
  197. if err != nil {
  198. break
  199. }
  200. continue
  201. }
  202. if start.Name.Local == "library_animations" {
  203. err = d.decLibraryAnimations(start, dom)
  204. if err != nil {
  205. break
  206. }
  207. continue
  208. }
  209. if start.Name.Local == "library_images" {
  210. err = d.decLibraryImages(start, dom)
  211. if err != nil {
  212. break
  213. }
  214. continue
  215. }
  216. if start.Name.Local == "library_effects" {
  217. err = d.decLibraryEffects(start, dom)
  218. if err != nil {
  219. break
  220. }
  221. continue
  222. }
  223. if start.Name.Local == "library_lights" {
  224. err = d.decLibraryLights(start, dom)
  225. if err != nil {
  226. break
  227. }
  228. continue
  229. }
  230. if start.Name.Local == "library_materials" {
  231. err = d.decLibraryMaterials(start, dom)
  232. if err != nil {
  233. break
  234. }
  235. continue
  236. }
  237. if start.Name.Local == "library_geometries" {
  238. err = d.decLibraryGeometries(start, dom)
  239. if err != nil {
  240. break
  241. }
  242. continue
  243. }
  244. if start.Name.Local == "library_visual_scenes" {
  245. err = d.decLibraryVisualScenes(start, dom)
  246. if err != nil {
  247. break
  248. }
  249. continue
  250. }
  251. if start.Name.Local == "scene" {
  252. err = d.decScene(start, dom)
  253. if err != nil {
  254. break
  255. }
  256. continue
  257. }
  258. }
  259. return err
  260. }
  261. func (d *Decoder) decContributor(start xml.StartElement, c *Contributor) error {
  262. for {
  263. child, data, err := d.decNextChild(start)
  264. if err != nil || child.Name.Local == "" {
  265. return err
  266. }
  267. if child.Name.Local == "author" {
  268. c.Author = string(data)
  269. continue
  270. }
  271. if child.Name.Local == "author_email" {
  272. c.AuthorEmail = string(data)
  273. continue
  274. }
  275. if child.Name.Local == "author_website" {
  276. c.AuthorWebsite = string(data)
  277. continue
  278. }
  279. if child.Name.Local == "authoring_tool" {
  280. c.AuthoringTool = string(data)
  281. continue
  282. }
  283. if child.Name.Local == "comments" {
  284. c.Comments = string(data)
  285. continue
  286. }
  287. if child.Name.Local == "copyright" {
  288. c.Comments = string(data)
  289. continue
  290. }
  291. if child.Name.Local == "source_data" {
  292. c.SourceData = string(data)
  293. continue
  294. }
  295. }
  296. }
  297. func (d *Decoder) decAsset(assetStart xml.StartElement, a *Asset) error {
  298. for {
  299. child, data, err := d.decNextChild(assetStart)
  300. if err != nil || child.Name.Local == "" {
  301. return err
  302. }
  303. if child.Name.Local == "contributor" {
  304. err := d.decContributor(child, &a.Contributor)
  305. if err != nil {
  306. return err
  307. }
  308. continue
  309. }
  310. if child.Name.Local == "created" {
  311. a.Created = string(data)
  312. continue
  313. }
  314. if child.Name.Local == "modified" {
  315. a.Modified = string(data)
  316. continue
  317. }
  318. if child.Name.Local == "up_axis" {
  319. a.UpAxis = string(data)
  320. continue
  321. }
  322. }
  323. return nil
  324. }
  325. func (d *Decoder) decScene(start xml.StartElement, dom *Collada) error {
  326. dom.Scene = new(Scene)
  327. for {
  328. child, _, err := d.decNextChild(start)
  329. if err != nil || child.Name.Local == "" {
  330. return err
  331. }
  332. if child.Name.Local == "instance_visual_scene" {
  333. err := d.decInstanceVisualScene(child, dom.Scene)
  334. if err != nil {
  335. return err
  336. }
  337. continue
  338. }
  339. }
  340. return nil
  341. }
  342. func (d *Decoder) decInstanceVisualScene(start xml.StartElement, s *Scene) error {
  343. vs := new(InstanceVisualScene)
  344. s.InstanceVisualScene = vs
  345. vs.Sid = findAttrib(start, "sid").Value
  346. vs.Name = findAttrib(start, "name").Value
  347. vs.Url = findAttrib(start, "url").Value
  348. return nil
  349. }