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