collada.go 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  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. func (c *Contributor) Dump(out io.Writer, indent int) {
  98. fmt.Fprintf(out, "%sContributor:\n", sIndent(indent))
  99. ind := indent + step
  100. if len(c.Author) > 0 {
  101. fmt.Fprintf(out, "%sAuthor:%s\n", sIndent(ind), c.Author)
  102. }
  103. if len(c.AuthorEmail) > 0 {
  104. fmt.Fprintf(out, "%sAuthorEmail:%s\n", sIndent(ind), c.AuthorEmail)
  105. }
  106. if len(c.AuthorWebsite) > 0 {
  107. fmt.Fprintf(out, "%sAuthorWebsite:%s\n", sIndent(ind), c.AuthorWebsite)
  108. }
  109. if len(c.AuthoringTool) > 0 {
  110. fmt.Fprintf(out, "%sAuthoringTool:%s\n", sIndent(ind), c.AuthoringTool)
  111. }
  112. if len(c.Comments) > 0 {
  113. fmt.Fprintf(out, "%sComments:%s\n", sIndent(ind), c.Comments)
  114. }
  115. if len(c.Copyright) > 0 {
  116. fmt.Fprintf(out, "%sCopyright:%s\n", sIndent(ind), c.Copyright)
  117. }
  118. if len(c.SourceData) > 0 {
  119. fmt.Fprintf(out, "%sSourceData:%s\n", sIndent(ind), c.SourceData)
  120. }
  121. }
  122. //
  123. // Asset
  124. //
  125. type Asset struct {
  126. Contributor Contributor
  127. Created string
  128. Modified string
  129. UpAxis string
  130. }
  131. func (a *Asset) Dump(out io.Writer, indent int) {
  132. fmt.Fprintf(out, "%sAsset:\n", sIndent(indent))
  133. ind := indent + step
  134. a.Contributor.Dump(out, ind)
  135. fmt.Fprintf(out, "%sCreated:%s\n", sIndent(ind), a.Created)
  136. fmt.Fprintf(out, "%sModified:%s\n", sIndent(ind), a.Modified)
  137. fmt.Fprintf(out, "%sUpAxis:%s\n", sIndent(ind), a.UpAxis)
  138. }
  139. //
  140. // Scene
  141. //
  142. type Scene struct {
  143. InstanceVisualScene *InstanceVisualScene
  144. }
  145. func (s *Scene) Dump(out io.Writer, indent int) {
  146. fmt.Fprintf(out, "%sScene:\n", sIndent(indent))
  147. ind := indent + step
  148. s.InstanceVisualScene.Dump(out, ind)
  149. }
  150. //
  151. // InstanceVisualScene
  152. //
  153. type InstanceVisualScene struct {
  154. Sid string
  155. Name string
  156. Url string
  157. }
  158. func (ivs *InstanceVisualScene) Dump(out io.Writer, indent int) {
  159. if ivs == nil {
  160. return
  161. }
  162. fmt.Fprintf(out, "%sInstanceVisualScene sid:%s name:%s url:%s\n",
  163. sIndent(indent), ivs.Sid, ivs.Name, ivs.Url)
  164. }
  165. func (d *Decoder) decCollada(dom *Collada) error {
  166. // Loop to read all first level elements
  167. var tok interface{}
  168. var err error
  169. first := true
  170. for {
  171. // Reads next token
  172. tok, err = d.xmldec.Token()
  173. if err == io.EOF {
  174. return nil
  175. }
  176. // If not a start element ignore and continue
  177. start, ok := tok.(xml.StartElement)
  178. if !ok {
  179. continue
  180. }
  181. // First element must be "COLLADA"
  182. if first {
  183. if start.Name.Local != "COLLADA" {
  184. return fmt.Errorf("Not a COLLADA file")
  185. }
  186. first = false
  187. dom.Version = findAttrib(start, "version").Value
  188. continue
  189. }
  190. // Decode specified start elements
  191. if start.Name.Local == "asset" {
  192. err = d.decAsset(start, &dom.Asset)
  193. if err != nil {
  194. break
  195. }
  196. continue
  197. }
  198. if start.Name.Local == "library_animations" {
  199. err = d.decLibraryAnimations(start, dom)
  200. if err != nil {
  201. break
  202. }
  203. continue
  204. }
  205. if start.Name.Local == "library_images" {
  206. err = d.decLibraryImages(start, dom)
  207. if err != nil {
  208. break
  209. }
  210. continue
  211. }
  212. if start.Name.Local == "library_effects" {
  213. err = d.decLibraryEffects(start, dom)
  214. if err != nil {
  215. break
  216. }
  217. continue
  218. }
  219. if start.Name.Local == "library_lights" {
  220. err = d.decLibraryLights(start, dom)
  221. if err != nil {
  222. break
  223. }
  224. continue
  225. }
  226. if start.Name.Local == "library_materials" {
  227. err = d.decLibraryMaterials(start, dom)
  228. if err != nil {
  229. break
  230. }
  231. continue
  232. }
  233. if start.Name.Local == "library_geometries" {
  234. err = d.decLibraryGeometries(start, dom)
  235. if err != nil {
  236. break
  237. }
  238. continue
  239. }
  240. if start.Name.Local == "library_visual_scenes" {
  241. err = d.decLibraryVisualScenes(start, dom)
  242. if err != nil {
  243. break
  244. }
  245. continue
  246. }
  247. if start.Name.Local == "scene" {
  248. err = d.decScene(start, dom)
  249. if err != nil {
  250. break
  251. }
  252. continue
  253. }
  254. }
  255. return err
  256. }
  257. func (d *Decoder) decContributor(start xml.StartElement, c *Contributor) error {
  258. for {
  259. child, data, err := d.decNextChild(start)
  260. if err != nil || child.Name.Local == "" {
  261. return err
  262. }
  263. if child.Name.Local == "author" {
  264. c.Author = string(data)
  265. continue
  266. }
  267. if child.Name.Local == "author_email" {
  268. c.AuthorEmail = string(data)
  269. continue
  270. }
  271. if child.Name.Local == "author_website" {
  272. c.AuthorWebsite = string(data)
  273. continue
  274. }
  275. if child.Name.Local == "authoring_tool" {
  276. c.AuthoringTool = string(data)
  277. continue
  278. }
  279. if child.Name.Local == "comments" {
  280. c.Comments = string(data)
  281. continue
  282. }
  283. if child.Name.Local == "copyright" {
  284. c.Comments = string(data)
  285. continue
  286. }
  287. if child.Name.Local == "source_data" {
  288. c.SourceData = string(data)
  289. continue
  290. }
  291. }
  292. }
  293. func (d *Decoder) decAsset(assetStart xml.StartElement, a *Asset) error {
  294. for {
  295. child, data, err := d.decNextChild(assetStart)
  296. if err != nil || child.Name.Local == "" {
  297. return err
  298. }
  299. if child.Name.Local == "contributor" {
  300. err := d.decContributor(child, &a.Contributor)
  301. if err != nil {
  302. return err
  303. }
  304. continue
  305. }
  306. if child.Name.Local == "created" {
  307. a.Created = string(data)
  308. continue
  309. }
  310. if child.Name.Local == "modified" {
  311. a.Modified = string(data)
  312. continue
  313. }
  314. if child.Name.Local == "up_axis" {
  315. a.UpAxis = string(data)
  316. continue
  317. }
  318. }
  319. return nil
  320. }
  321. func (d *Decoder) decScene(start xml.StartElement, dom *Collada) error {
  322. dom.Scene = new(Scene)
  323. for {
  324. child, _, err := d.decNextChild(start)
  325. if err != nil || child.Name.Local == "" {
  326. return err
  327. }
  328. if child.Name.Local == "instance_visual_scene" {
  329. err := d.decInstanceVisualScene(child, dom.Scene)
  330. if err != nil {
  331. return err
  332. }
  333. continue
  334. }
  335. }
  336. return nil
  337. }
  338. func (d *Decoder) decInstanceVisualScene(start xml.StartElement, s *Scene) error {
  339. vs := new(InstanceVisualScene)
  340. s.InstanceVisualScene = vs
  341. vs.Sid = findAttrib(start, "sid").Value
  342. vs.Name = findAttrib(start, "name").Value
  343. vs.Url = findAttrib(start, "url").Value
  344. return nil
  345. }